Skip to main content
Skip table of contents

Visually hidden link and button text best practices

Last Updated: July 7, 2025

When the visual name of a link or button isn’t descriptive enough for screen readers, we typically use aria-label or aria-labelledby to create a more specific accessible name.

This can be an issue for users of speech recognition applications, who may struggle to select interactive elements when the visual name doesn't match the accessible name.

This page details best practices for creating accessible names that work for all users.

Glossary

Speech recognition applications

Built-in or third-party apps that allow users to control their devices by using their voice. This includes navigating websites and filling out online forms. Also known as “voice command applications.”

Apps include Dragon (Windows, third-party), Voice Control (Mac and iOS, built-in), and Speech Recognition (Windows 10, built-in).

Example: to activate a link with the visible name “My Profile” on a web page, a user of a voice command app can say “Click ‘My Profile.’” to activate the link.

For more about how speech recognition applications work, read Speech recognition instructions and troubleshooting during research.

Accessible name (accName)

From W3.org:

The name of a user interface element. The value of the accessible name may be derived from a visible (e.g., the visible text on a button) or invisible (e.g., the text alternative that describes an icon) property of the user interface element.

aria-label, aria-labelledby

ARIA methods for defining an element’s accessible name, used when the design doesn’t allow for unique visible text strings

Why non-visible accessible names can be an issue

VA.gov often uses non-visible accessible names to enhance the accessibility a web page.

A common example are VA’s form review pages.

  • These pages allow users to edit their form entries before submission.

  • Each form section has an edit button. The visible name of each button is “Edit.”

  • Since duplicate “Edit” buttons have no context (what is being edited?), we use an aria-label to create an accessible name for each button. The "Edit" button under "Personal information" has an aria-label of "Edit personal information." This allows screen reader users to determine the intent of each button.

But this can be an issue for voice command users who try to select a link or button.

  • Some applications only allow users to use a non-visible accessible name (if present) to select elements on the page.

  • Some only use the visual name. For those apps, if a user tries the accessible name, it won’t work.

  • Some allow for a mix of both, drawing from the visible and accessible name to make a selection.

This results in an inconsistent experience for these users.

How to use non-visible accessible names

First, review your design. If possible, use distinct visual names for each link / button on a screen. This avoids the issue of needing aria-label or aria-labelledby entirely.

If your design doesn’t allow for this and you must use a non-visible accessible name, follow these guidelines:

  1. Create the accessible name. If there’s a visible name, the accessible name must start with that name.

    1. Correct: A button with the visible name “Edit” is given the accessible name “Edit personal information”

    2. Incorrect: A button with the visible name “Submit” is given the accessible name “Please submit the form”

  2. Add the accessible name using the correct method.

    1. VADS components: Use the component’s built-in prop.

      1. Check the prop list for the component in Storybook. For example, the Button component has a label prop, which is defined as “The aria-label of the component.”

      2. If the component doesn’t have an aria-label equivalent, you can’t create a non-visible accessible name for that component.

      3. Don’t use “aria-label” - the component will only recognize built-in props.

    2. Custom code: Use one of these three options, in this order:

      1. aria-labelledby with visible text

        1. Accessible names created with aria-labelledby are machine translatable. Since they “live” in the actual text of the page, if you need to edit that text, the accessible name will be edited too!

        2. In this example, the button’s accessible name is “Edit Personal information”

          CODE
          <h2 id="theHeading">Personal information</h2>
          <button id="theButton" aria-labelledby="theButton theHeading">Edit</button>
      2. aria-labelledby and the .vads-u-visibility--screen-reader class

        1. If you don’t have visible text to work with, you can create some visually hidden text using the VADS .vads-u-visibility--screen-reader utility class. Put it in a container, give it an ID, and reference it.

        2. In this example, the link’s accessible name is “Hello Friend”

          CODE
          <div id="someText" class="vads-u-visibility--screen-reader"> Friend</div>
          <a href="#" id="moreText" aria-labelledby="someText moreText">Hello</a>
      3. aria-label - only use if necessary

        1. Like alt, aria-label is generally not translated by machine translation because the label is in an HTML attribute.

        2. If you use aria-label, remember to edit it if necessary. Since aria-label isn’t visible and is “trapped” as an attribute, it’s often forgotten about after initial development.

Resources


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.