Skip to content

Make it Accessible: Better Layout with HTML

Make it Accessible: Better Layout with HTML

Make it Accessible - 8 Part Series

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Make it Accessible: Better layouts with HTML

In this article, I'm going to teach you how to use the HTML tags <div>, <section> and <article>, and how they can improve your web applications accessibility.

Here you can access all the resources used in the article.

The Problem

Web applications are built with HTML, and even though it isn't a programming language, it is nontheless complex. One of the first issues you may encounter is knowing which element to use, and the huge amount of elements available makes this issue even more challenging.

When it comes to your page's layout, some of the options are; <div>, <section> and <article>. Today, you're going to learn when you should use each of them.

The Solution

First, we will conceptualize each of the elements I just mentioned. You can learn more about these in the w3c wai aria practices guide, but let's discuss those concepts here:

The <div> element is often used as a container for other HTML elements to style them with CSS or to perform certain tasks with JavaScript. w3schools.com

You may be tempted to use <div> with some styles instead of learning about the available elements in HTML5. I have to tell you, if you do that, you're hurting your users. Each element has a specific purpose, and you should be using the right element. <div> is useful when you want to group some elements and give them some styling, that doesn't mean you should make everything with <div>.

The <section> tag defines sections in a document, such as chapters, headers, footers, or any other sections of the document. w3school.com

This is a very important tag as you start your accessibility journey. It gives context to your users, specially those with Screen Readers. By "context", I mean that if you wrap a group of elements with a section and give it an accessible name, once users focus one of the elements, it reads the parent container too.

The <article> tag specifies independent, self-contained content. w3school.com

Almost every application has some kind of catalogue showing several items having the same styles, and if you think it through, these items could be placed anywhere without any context. Articles are cool for those cases, even though these aren't landmarks, it's common for Screen Readers to have a mechanism to allow users to navigate through articles easily.

The Implementation

Next, we're going to do a small sample using each of the mentioned elements. Let's start with the <div>.

Using divs right

Now that you are fully aware of the purpose of a <div>, it is time to use it. For this one, I decided to take the easy road and make a very simple example. Let's say you have multiple "things" you want to group, and to which you want to apply some additional styling. That can be easily done like this:

<html>
  <head>
    <style>
      .square {
        display: inline-block;
        width: 150px;
        height: 150px;
        border: 1px solid black;
        margin: 10px;
        background-color: white;
      }

      .group {
        display: inline-block;
        margin: 0;
        background-color: #bbb;
      }
    </style>
  </head>

  <body>
    <header>
      <h1>Using divs right</h1>
    </header>

    <main>
      <div class="group">
        <div class="square"></div>
        <div class="square"></div>
      </div>
      <div class="square"></div>
      <div class="square"></div>
      <div class="square"></div>
    </main>
  </body>
</html>

To test this, create a file with the .html extension containing what I just gave you, and open it with your preferred browser. You'll notice that the first two have a light gray background. Once again, very simple and easy to follow. Let's jump to the next example.

Sections are the way to go

For this one, I was looking for a more exciting example. Let's say you are building an application for a movie theater that allows customers to order tickets online. If you buy a ticket, you want to have a page where you can see all the details about the movie and your ticket.

Let's start by thinking it through. We want to see all the information about the movie, title, synopsis, a banner image, and a genre. When it comes to the ticket, I want to see its worth, my seat number, and the time left for the show to start.

The HTML for something like this would look like this:

<html>
  <head>
    <style>
      body {
        margin: 0;
        padding: 0;
      }

      main {
        display: flex;
        align-items: flex-start;
        justify-content: center;
        flex-wrap: wrap;
        background-color: #333;
        min-height: calc(100vh - 80px);
        margin-top: 80px;
      }

      header {
        position: absolute;
        height: 80px;
        color: white;
        background-color: #444;
        padding: 2px 0;
        text-align: center;
        box-shadow: 0px 6px 3px 3px rgba(0, 0, 0, 0.1);
        width: 100%;
        top: 0px;
      }

      .card {
        box-shadow: 0px 6px 3px 3px rgba(0, 0, 0, 0.1);
        display: inline-block;
        margin: 20px;
      }

      .movie-details {
        width: 400px;
      }

      .movie-details figure {
        width: 100%;
        margin: 0;
      }

      .movie-details figure img {
        width: 100%;
        object-fit: cover;
      }

      .container {
        padding: 10px;
        border: 1px solid #333;
        background-color: #444;
        color: white;
      }

      .ticket-summary {
        width: 250px;
      }

      .ticket-summary dt {
        color: #ccc;
        font-size: 1.1rem;
        font-weight: bold;
        margin-top: 8px;
      }
    </style>
  </head>

  <body>
    <header>
      <h1>Your Ticket Details</h1>
    </header>

    <main>
      <section class="card movie-details" aria-label="movie details">
        <figure>
          <img src="./img.jpg" alt="" />
        </figure>

        <div class="container">
          <h2 style="margin: 6px 0;">Parasite</h2>
          <p style="text-align: justify;">
            Greed and class discrimination threaten the newly formed symbiotic
            relationship between the wealthy Park family and the destitute Kim
            clan.
          </p>
          <p><b>Comedy, Drama</b></p>
        </div>
      </section>

      <section
        class="card ticket-summary"
        aria-labelledby="ticket-summary-title"
        aria-describedby="ticket-summary-description"
      >
        <div class="container">
          <h2
            id="ticket-summary-title"
            style="margin: 6px 0; text-align: center;"
          >
            Ticket Summary
          </h2>
          <p id="ticket-summary-description" style="text-align: justify;">
            Remember to exchange your ticket identifier for the actual ticket as
            soon as you get to the movie theater.
          </p>
          <dl>
            <dt>Identifier</dt>
            <dd>123</dd>
            <dt>Seat</dt>
            <dd>B-12</dd>
            <dt>Price</dt>
            <dd>$ 2,00 USD</dd>
            <dt>Starts in</dt>
            <dd>2h 30m</dd>
          </dl>
        </div>
      </section>
    </main>
  </body>
</html>

For now you can ignore the styles, it's just to make it look less ugly, what I want you to pay attention to is the HTML part. Look at how I created two sections- one for the movie details, and one for the ticket summary. Another important takeaway is how I used aria-label and aria-labelledby. Both have the same results, but in the movie details, I wanted to read "Movie Details" instead of the movie title, and in the case of the Ticket Summary, it's different because we want to read the same title.

By structuring your HTML document this way, using sections with the proper accessible names, you're not only giving context to the user, but you're creating a hierachical view of the landmarks of your application. This makes it easier for Screen Readers to understand your page, and as a consequence, you get better usability for your disabled users.

Articles are useful too

I know that example may have set the bar a little high. For this example, I'm doing something simpler. Let's say that this movie theater we are "working for" wants to show all the available movies to possible customers. This is where articles shine the most, because let's face it, no matter how many movies there are, all of them will have the same styles.

Let's roll up our sleeves, and create a new html file with this content:

<html>
  <head>
    <style>
      body {
        margin: 0;
        padding: 0;
      }

      main {
        display: flex;
        align-items: flex-start;
        justify-content: center;
        flex-wrap: wrap;
        background-color: #333;
        min-height: calc(100vh - 80px);
        margin-top: 80px;
      }

      header {
        position: absolute;
        height: 80px;
        color: white;
        background-color: #444;
        padding: 2px 0;
        text-align: center;
        box-shadow: 0px 6px 3px 3px rgba(0, 0, 0, 0.1);
        top: 0px;
        width: 100%;
      }

      .card {
        box-shadow: 0px 6px 3px 3px rgba(0, 0, 0, 0.1);
        display: inline-block;
        margin: 20px;
      }

      .movies {
        display: flex;
        justify-content: center;
        flex-wrap: wrap;
        width: 800px;
      }

      .feed {
        display: flex;
        margin-top: 10px;
      }

      .movie {
        width: 200px;
        height: 420px;
      }

      .movie figure {
        width: 100%;
        height: 300px;
        margin: 0;
        overflow: hidden;
      }

      .movie figure img {
        width: 100%;
        object-fit: cover;
        height: 100%;
      }

      .container {
        padding: 10px;
        height: 100px;
        border: 1px solid #333;
        background-color: #444;
        color: white;
      }

      .movie h2 {
        margin: 8px 0;
        font-size: 1.2rem;
        font-weight: bold;
      }

      .movie p {
        margin: 8px 0;
        font-style: italic;
      }
    </style>
  </head>

  <body>
    <header>
      <h1>Movies List</h1>
    </header>

    <main>
      <section class="movies" aria-label="available movies">
        <div role="feed" class="feed">
          <article
            class="movie card"
            aria-labelledby="movie-name-1"
            aria-describedby="movie-genre-1"
            tabindex="0"
            aria-posinset="1"
            aria-setsize="3"
          >
            <figure>
              <img src="./movie-1.jpg" alt="" />
            </figure>
            <div class="container">
              <h2 id="movie-name-1">The Shawshank Redemption</h2>
              <p id="movie-genre-1">Drama</p>
            </div>
          </article>
          <article
            class="movie card"
            aria-labelledby="movie-name-2"
            aria-describedby="movie-genre-2"
            tabindex="0"
            aria-posinset="2"
            aria-setsize="3"
          >
            <figure>
              <img src="./movie-2.jpg" alt="" />
            </figure>
            <div class="container">
              <h2 id="movie-name-2">The Godfather</h2>
              <p id="movie-genre-2">Crime, Drama</p>
            </div>
          </article>
          <article
            class="movie card"
            aria-labelledby="movie-name-3"
            aria-describedby="movie-genre-3"
            tabindex="0"
            aria-posinset="3"
            aria-setsize="3"
          >
            <figure>
              <img src="./movie-3.jpg" alt="" />
            </figure>
            <div class="container">
              <h2 id="movie-name-3">The Dark Knight</h2>
              <p id="movie-genre-3">Crime, Drama</p>
            </div>
          </article>
        </div>
      </section>
    </main>
  </body>
</html>

Remember to focus on the HTML structure, not the styles. The first time I saw this kind of code, I was like, wow, what's all that aria stuff doing? Today, I'm going to make this easier for you.

First of all, I have to remind you that all of these ideas come from the WAI ARIA Authoring Practice Guide.

One thing to notice before heading to the code is that a list of movies is a feed. Also, don't reinvent the wheel. The WAI ARIA guide has a very detailed description of how a feed should be implemented while prioritizing accessibility. You have to start with <div> and role="feed", next you have to work on the articles.

Setting up the feed container is very simple. What's not so straightforward are the articles themselves. Each of the aria properties has a specific purpose:

  • aria-labelledby: Title of the movie.
  • aria-describedby: Additional information about the movie.
  • aria-posinset: Position of the movie in the list.
  • aria-setsize: Size of the list of movies.

There's also a tabindex="0" because once in a feed, screen readers provide users with additional navigation mechanisms that require us to make the articles "focusable".

NOTE: All the <img> in the samples have an empty alt like this alt="". It's because using an empty alt tells screen readers to ignore the images entirely, in a real life project for images that provide information, you always give a proper alt value.

Conclusion

Every time I write one of these series, I come up with the same conclusion: Just use HTML! I'm even thinking of changing the name to "It's Already Accessible". It's common to hear developers saying that HTML is too simple. It might be for some, but you still have to learn it. Whenever you write an application, try to build it following patterns like the ones in WAI-ARIA. Make sure to follow their specifications, and you'll make applications all of your users will love.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

The HTML Dialog Element: Enhancing Accessibility and Ease of Use cover image

The HTML Dialog Element: Enhancing Accessibility and Ease of Use

The HTML Dialog Element: Enhancing Accessibility and Ease of Use Dialogs are a common component added to applications, whether on the web or in native applications. Traditionally there has not been a standard way of implementing these on the web, resulting in many ad-hoc implementations that don’t act consistently across different web applications. Often, commonly expected features are missing from dialogs due to the complexity of implementing them. However, web browsers now offer a standard dialog element. Why use the dialog element? The native dialog element streamlines the implementation of dialogs, modals, and other kinds of non-modal dialogs. It does this by implementing many of the features needed by dialogs for you that are already baked into the browser. This is helpful as it reduces the burden on the developer when making their applications accessible by ensuring that user expectations concerning interaction are met, and it can also potentially simplify the implementation of dialogs in general. Basic usage Adding a dialog using the new tag can be achieved with just a few lines of code. ` However, adding the dialog alone won’t do anything to the page. It will show up only once you call the .showModal() method against it. ` Then if you want to close it you can call the .close() method on the dialog, or press the escape key to close it, just like most other modals work. Also, note how a backdrop appears that darkens the rest of the page and prevents you from interacting with it. Neat! Accessibility and focus management Correctly handling focus is important when making your web applications accessible to all users. Typically you have to move the current focus to the active dialog when showing them, but with the dialog element that’s done for you. By default, the focus will be set on the first focusable element in the dialog. You can optionally change which element receives focus first by setting the autofocus attribute on the element you want the focus to start on, as seen in the previous example where that attribute was added to the close element. Using the .showModal() method to open the dialog also implicitly adds the dialog ARIA role to the dialog element. This helps screen readers understand that a modal has appeared and the screen so it can act accordingly. Adding forms to dialogs Forms can also be added to dialogs, and there’s even a special method value for them. If you add a element with the method set to dialog then the form will have some different behaviors that differ from the standard get and post form methods. First off, no external HTTP request will be made with this new method. What will happen instead is that when the form gets submitted, the returnValue property on the form element will be set to the value of the submit button in the form. So given this example form: ` The form element with the example-form id will have its returnValue set to Submit. In addition to that, the dialog will close immediately after the submit event is done being handled, though not before automatic form validation is done. If this fails then the invalid event will be emitted. You may have already noticed one caveat to all of this. You might not want the form to close automatically when the submit handler is done running. If you perform an asynchronous request with an API or server you may want to wait for a response and show any errors that occur before dismissing the dialog. In this case, you can call event.preventDefault() in the submit event listener like so: ` Once your desired response comes back from the server, you can close it manually by using the .close() method on the dialog. Enhancing the backdrop The backdrop behind the dialog is a mostly translucent gray background by default. However, that backdrop is fully customizable using the ::backdrop pseudo-element. With it, you can set a background-color to any value you want, including gradients, images, etc. You may also want to make clicking the backdrop dismiss the modal, as this is a commonly implemented feature of them. By default, the &lt;dialog> element doesn’t do this for us. There are a couple of changes that we can make to the dialog to get this working. First, an event listener is needed so that we know when the user clicks away from the dialog. ` Alone this event listener looks strange. It appears to dismiss the dialog whenever the dialog is clicked, not the backdrop. That’s the opposite of what we want to do. Unfortunately, you cannot listen for a click event on the backdrop as it is considered to be part of the dialog itself. Adding this event listener by itself will effectively make clicking anywhere on the page dismiss the dialog. To correct for this we need to wrap the contents of the dialog content with another element that will effectively mask the dialog and receive the click instead. A simple element can do! ` Even this isn’t perfect though as the contents of the div may have elements with margins in them that will push the div down, resulting in clicks close to the edges of the dialog to dismiss it. This can be resolved by adding a couple of styles the the wrapping div that will make the margin stay contained within the wrapper element. The dialog element itself also has some default padding that will exacerbate this issue. ` The wrapping div can be made into an inline-block element to contain the margin, and by moving the padding from the parent dialog to the wrapper, clicks made in the padded portions of the dialog will now interact with the wrapper element instead ensuring it won’t be dismissed. Conclusion Using the dialog element offers significant advantages for creating dialogs and modals by simplifying implementation with reasonable default behavior, enhancing accessibility for users that need assistive technologies such as screen readers by using automatic ARIA role assignment, tailored support for form elements, and flexible styling options....

Testing Accessibility Features With Playwright cover image

Testing Accessibility Features With Playwright

Testing Accessibility Features With Playwright In one of my previous posts, I mentioned the importance of having e2e tests to verify that your keyboard navigation works properly. I also suggested Playwright as a tool to write those tests. I owe you a little tutorial on how to do that. And because keyboard navigation is not the only accessibility feature you should test and since Playwright has some nice built-in tools for accessibility testing, I will also show you how to test other aspects of your website. What is Playwright? Let's start with a short introduction for those who don't know Playwright yet. Playwright is an open-source automation library developed by Microsoft, designed to enable developers and testers to write scripts that can control a web browser's behavior. It is a Node.js library that provides a high-level API to control headless Chrome, Firefox, and WebKit with a single interface. This means you can write your tests once and run them in multiple browsers, ensuring cross-browser compatibility. If you're new to Playwright, you can check out Dane's article, which nicely introduces the basics such as configuration or selectors, and presents some nice test examples. Keyboard Accessibility Testing Now, as promised, let's dive into keyboard accessibility testing with Playwright. As I already mentioned, keyboard navigation is one of the most important accessibility features to test, given that it can break anytime you add new functionality to your application and the problem can easily go unnoticed. It is also one of the easiest to test with Playwright because it provides a neat keyboard API that allows you to simulate keyboard input and verify that the correct elements are focused or activated. Verifying Element Focus To check which element is selected after a series of keyboard inputs, you can use the toBeFocused() method to check whether it is focused or not, like this: ` This code snippet simulates pressing the Tab key three times and then checks that an input is focused. It then presses the Tab key again, verifying that the input is no longer focused. If you read my previous article, you might remember that I mentioned that many websites have a bug that prevents you from tabbing out of a textbox. This simple test can catch this bug and prevent headaches for your users. Simulating Complex Keyboard Interactions Playwright's keyboard class provides a keyboard.press() method to simulate pressing a key and releasing it immediately. It allows you to simulate pressing a single key, a combination of keys, or a key combination with a modifier key: ` You can find the full list of keys you can pass to the keyboard.press function on MDN. If you need finer control over the keyboard, you can use the keyboard.down() and keyboard.up() methods to simulate pressing and releasing a key separately. One use case for this is to simulate pressing a key and holding it down for a certain amount of time, such as holding the Shift key to select multiple elements or lines of text: ` You can also use the keyboard.insertText() method to insert text into an element, but note that modifier keys _do not affect_ this method (e.g. holding down the Shift key will not type the text uppercase) and it only dispatches the input event and does not emit the keydown, keyup or keypress events. ` The keyboard API allows you to test keyboard input, keyboard shortcuts; and ensure that your application responds correctly to user input without a mouse. Although this might seem unnecessary, believe me when I say it is not. As I mentioned in my previous article, many applications try to implement keyboard navigation but contain a nasty bug that renders the effort useless. And it is worth spending some time writing a few simple e2e tests to avoid invalidating your efforts. Testing Other Accessibility Features This article focuses mostly on keyboard accessibility, but I have good news! You can easily test other accessibility aspects with Playwright too! It conveniently integrates with the axe accessibility testing engine using the @axe-core/playwright package to run automated accessibility tests. These tests can catch various issues, such as poor color contrast, missing labels on UI controls, and duplicate IDs that can confuse assistive technologies. Example Test for Entire Page Accessibility Here's how you can scan your entire page for accessibility issues using Playwright: ` Scanning Specific Page Sections You can also target specific parts of your page by using AxeBuilder.include() to focus the accessibility scan: ` Handling Known Accessibility Issues When you have known accessibility issues that you cannot immediately fix, Playwright allows you to exclude certain elements from scans or disable specific rules: ` Reporting Accessibility Issues If you want to report accessibility issues in your test results, you can use the testInfo.attach() method to attach the scan results to your test report: ` You can then use reporters to embed or link the scan results in your test output. Conclusion While your e2e tests should not serve as a replacement for manual testing and you should still check your app yourself to catch any issues that automated tests won't reveal, Playwright provides a convenient way to automate checks whether all of your website's accessibility features work as intended. It allows you to test keyboard navigation and other accessibility aspects such as color contrast or missing labels to make sure you aren't shipping a broken experience. Testing accessibility with Playwright requires little effort, and in my opinion, is very much worth it. So, if you haven't done so yet, I encourage you to give it a try! And if you're still unconvinced, read about how I broke my hand to appreciate the importance of accessibility....

Lessons from the DOGE Website Hack: How to Secure Your Next.js Website cover image

Lessons from the DOGE Website Hack: How to Secure Your Next.js Website

Lessons from the DOGE Website Hack: How to Secure Your Next.js Website The Department of Government Efficiency (DOGE) launched a new website, doge.gov. Within days, it was defaced with messages from hackers. The culprit? A misconfigured database was left open, letting anyone edit content. Reports suggest the site was built on Cloudflare Pages, possibly with a Next.js frontend pulling data dynamically. While we don’t have the tech stack confirmed, we are confident that Next.js was used from early reporting around the website. Let’s dive into what went wrong—and how you can secure your own Next.js projects. What Happened to DOGE.gov? The hack was a classic case of security 101 gone wrong. The database—likely hosted in the cloud—was accessible without authentication. No passwords, no API keys, no nothing. Hackers simply connected to it and started scribbling their graffiti. Hosted on Cloudflare Pages (not government servers), the site might have been rushed, skipping critical security checks. For a .gov domain, this is surprising—but it’s a reminder that even big names can miss best practices. It’s easy to imagine how this happened: an unsecured server action is being used on the client side, a serverless function or API route fetching data from an unsecured database, no middleware enforcing access control, and a deployment that didn’t double-check cloud configs. Let’s break down how to avoid this in your own Next.js app. Securing Your Next.js Website: 5 Key Steps Next.js is a powerhouse for building fast, scalable websites, but its flexibility means you’re responsible for locking the doors. Here’s how to keep your site safe. 1. Double-check your Server Actions If Next.js 13 or later was used, Server Actions might’ve been part of the mix—think form submissions or dynamic updates straight from the frontend. These are slick for handling server-side logic without a separate API, but they’re a security risk if not handled right. An unsecured Server Action could’ve been how hackers slipped into the database. Why? Next.js generates a public endpoint for each Server Action. If these Server Actions lack proper authentication and authorization measures, they become vulnerable to unauthorized data access. Example: * Restrict Access: Always validate the user’s session or token before executing sensitive operations. * Limit Scope: Only allow Server Actions to perform specific, safe tasks—don’t let them run wild with full database access. * Don’t use server action on the client side without authorization and authentication checks 2. Lock Down Your Database Access Another incident happened in 2020. A hacker used an automated script to scan for misconfigured MongoDB databases, wiping the content of 23 thousand databases that have been left wide open, and leaving a ransom note behind asking for money. So whether you’re using MongoDB, PostgreSQL, or Cloudflare’s D1, never leave it publicly accessible. Here’s what to do: * Set Authentication: Always require credentials (username/password or API keys) to connect. Store these in environment variables (e.g., .env.local for Next.js) and access them via process.env. * Whitelist IPs: If your database is cloud-hosted, restrict access to your Next.js app’s server or Vercel deployment IP range. * Use VPCs: For extra security, put your database in a Virtual Private Cloud (VPC) so it’s not even exposed to the public internet. If you are using Vercel, you can create private connections between Vercel Functions and your backend cloud, like databases or other private infrastructure, using Vercel Secure Compute Example: In a Next.js API route (/app/api/data.js): ` > Tip: Don’t hardcode MONGO_URI—keep it in .env and add .env to .gitignore. 3. Secure Your API Routes Next.js API routes are awesome for server-side logic, but they’re a potential entry point if left unchecked. The site might’ve had an API endpoint feeding its database updates without protection. * Add Authentication: Use a library like next-auth or JSON Web Tokens (JWT) to secure routes. * Rate Limit: Prevent abuse with something like rate-limiter-flexible. Example: ` 4. Double-Check Your Cloud Config A misconfigured cloud setup may have exposed the database. If you’re deploying on Vercel, Netlify, or Cloudflare: * Environment Variables: Store secrets in your hosting platform’s dashboard, not in code. * Serverless Functions: Ensure they’re not leaking sensitive data in responses. Log errors, not secrets. * Access Controls: Verify your database firewall rules only allow connections from your app. 5. Sanitize and Validate Inputs Hackers love injecting junk into forms or APIs. If your app lets users submit data (e.g., feedback forms), unvalidated inputs could’ve been a vector. In Next.js: * Sanitize: Use libraries like sanitize-html for user inputs. * Validate: Check data types and lengths before hitting your database. Example: ` Summary The DOGE website hack serves as a reminder of the ever-present need for robust security measures in web development. By following the outlined steps–double-checking Server Actions, locking down database access, securing API routes, verifying cloud configurations, and sanitizing/validating inputs–you can enhance the security posture of your Next.js applications and protect them from potential threats. Remember, a proactive approach to security is always the best defense....

“ChatGPT knows me pretty well… but it drew me as a white man with a man bun.” – Angie Jones on AI Bias, DevRel, and Block’s new open source AI agent “goose” cover image

“ChatGPT knows me pretty well… but it drew me as a white man with a man bun.” – Angie Jones on AI Bias, DevRel, and Block’s new open source AI agent “goose”

Angie Jones is a veteran innovator, educator, and inventor with over twenty years of industry experience and twenty-seven digital technology patents both domestically and internationally. As the VP of Developer Relations at Block, she facilitates developer training and enablement, delivering tools for developer users and open source contributors. However, her educational work doesn’t end with her day job. She is also a contributor to multiple books examining the intersection of technology and career, including DevOps: Implementing Cultural Change, and 97 Things Every Java Programmer Should Know, and is an active speaker in the global developer conference circuit. With the release of Block’s new open source AI agent “goose”, Angie drives conversations around AI’s role in developer productivity, ethical practices, and the application of intelligent tooling. We had the chance to talk with her about the evolution of DevRel, what makes a great leader, emergent data governance practices, women who are crushing it right now in the industry, and more: Developer Advocacy is Mainstream A decade ago, Developer Relations (DevRel) wasn’t the established field it is today. It was often called Developer Evangelism, and fewer companies saw the value in having engineers speak directly to other engineers. > “Developer Relations was more of a niche space. It’s become much more mainstream these days with pretty much every developer-focused company realizing that the best way to reach developers is with their peers.” That shift has opened up more opportunities for engineers who enjoy teaching, community-building, and breaking down complex technical concepts. But because DevRel straddles multiple functions, its place within an organization remains up for debate—should it sit within Engineering, Product, Marketing, or even its own department? There’s no single answer, but its cross-functional nature makes it a crucial bridge between technical teams and the developers they serve. Leadership Is Not an Extension of Engineering Excellence Most engineers assume that excelling as an IC is enough to prepare them for leadership, but Angie warns that this is a common misconception. She’s seen firsthand how technical skills don’t always equate to strong leadership abilities—we’ve all worked under leaders who made us wonder *how they got there*. When she was promoted into leadership, Angie was determined not to become one of those leaders: > “This required humility. Acknowledging that while I was an expert in one area, I was a novice in another.” Instead of assuming leadership would come naturally, she took a deliberate approach to learning—taking courses, reading books, and working with executive coaches to build leadership skills the right way. Goose: An Open Source AI Assistant That Works for You At Block, Angie is working on a tool called goose, an open-source AI agent that runs locally on your machine. Unlike many AI assistants that are locked into specific platforms, goose is designed to be fully customizable: > “You can use your LLM of choice and integrate it with any API through the Model Context Protocol (MCP).” That flexibility means goose can be tailored to fit developers’ workflows. Angie gives an example of what this looks like in action: > “Goose, take this Figma file and build out all of the components for it. Check them into a new GitHub repo called @org/design-components and send a message to the #design channel in Slack informing them of the changes.” And just like that, it’s done— no manual intervention required. The Future of Data Governance As AI adoption accelerates, data governance has become a top priority for companies. Strong governance requires clear policies, security measures, and accountability. Angie points out that organizations are already making moves in this space: > “Cisco recently launched a product called AI Defense to help organizations enhance their data governance frameworks and ensure that AI deployments align with established data policies and compliance requirements.” According to Angie, in the next five years, we can expect more structured frameworks around AI data usage, especially as businesses navigate privacy concerns and regulatory compliance. Bias in AI Career Tools: Helping or Hurting? AI-powered resume screeners and promotion predictors are becoming more common in hiring, but are they helping or hurting underrepresented groups? Angie’s own experience with AI bias was eye-opening: > “I use ChatGPT every day. It knows me pretty well. I asked it to draw a picture of what it thinks my current life looks like, and it drew me as a white male (with a man bun).” When she called it out, the AI responded: > “No, I don’t picture you that way at all, but it sounds like the illustration might’ve leaned into the tech stereotype aesthetic a little too much.” This illustrates a bigger problem— AI often reflects human biases at scale. However, there are emerging solutions, such as identity masking, which removes names, race, and gender markers so that only skills are evaluated. > “In scenarios like this, minorities are given a fairer shot.” It’s a step toward a more equitable hiring process, but it also surfaces the need for constant vigilance in AI development to prevent harmful biases. Women at the Forefront of AI Innovation While AI is reshaping nearly every industry, women are playing a leading role in its development. Angie highlights several technologists: > “I’m so proud to see women are already at the forefront of AI innovation. I see amazing women leading AI research, training, and development such as Mira Murati, Timnit Gebru, Joelle Pineau, Meredith Whittaker, and even Block’s own VP of Data & AI, Jackie Brosamer.” These women are influencing not just the technical advancements in AI but also the ethical considerations that come with it. Connect with Angie Angie Jones is an undeniable pillar of the online JavaScript community, and it isn’t hard to connect with her! You can find Angie on X (Twitter), Linkedin, or on her personal site (where you can also access her free Linkedin Courses). Learn more about goose by Block....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co