A link takes someone to a resource or location. A button performs an action, such as saving a form, opening a dialog, or revealing details. Choosing between them starts with what the person expects to happen—not with how the control looks.

A control should tell the same basic truth through its element, appearance, name, and behavior. When those parts agree, people can more reliably recognize and use it with a keyboard, pointer, touchscreen, screen reader, or speech-input tool.

This article connects two decisions that are often handled separately: choosing the right HTML element and giving that element a clear, accessible name.

Ask a plain-language question: Is the person going somewhere, or asking the interface to do something?

  • Use a link for a destination: an article, account page, document, or section of the current page.
  • Use a button for an action: submit, save, delete, play, pause, reveal, close, or open a dialog.

The URL alone does not settle the question. A link can navigate within a JavaScript application without a full page reload. A button can submit information and lead to another page. What matters is the intended action and the browser behavior that should accompany it.

Similar appearance, different purpose

These controls might share the same visual styling, but they make different promises:

<a href="/account/" class="control">View account</a>

<button type="button" class="control">Edit account details</button>

The link identifies an account page. The button could open an editing dialog in the current interface. The button still needs application code to implement that action; its text alone does not create a dialog.

Shared styling is not inherently a problem. A prominent navigation link can look like a button while remaining a link in HTML. However, visual design should still help people distinguish controls from ordinary text and understand what will happen.

When the boundary needs more thought

Consider a control labeled “View report.” If it navigates to a report page, use a link. If it opens a report preview dialog, use a button—and consider a more specific label such as “Preview report.” If it generates a new report from selected data, a button labeled “Generate report” communicates that process more accurately.

For navigation within the current page, an anchor link is usually appropriate:

<a href="#maintenance-schedule">View the maintenance schedule</a>

Revealing a collapsed maintenance schedule is a different operation. That calls for a disclosure control, such as a button with an expanded state or an appropriate native details and summary implementation.

Use native elements for native behavior

Native HTML provides more than an element name. It supplies behavior that browsers and assistive technologies already understand. This is one reason semantic HTML is a functional foundation rather than a labeling exercise.

What a real link provides

An a element with an href supplies a destination and participates in normal browser navigation. Depending on the browser, device, and destination, people can follow it, copy its address, open it in another tab, or use a context menu.

A focused link normally activates with Enter. Space normally scrolls the page rather than activating the link.

An anchor without an href is not an equivalent interactive link. Likewise, href="#" is not a neutral substitute for button behavior: it is a fragment destination that can affect the URL or scroll position.

What a native button provides

A native button provides button semantics, normal keyboard focusability, activation with Enter and Space, and support for features such as disabled states and form submission.

Choose its type deliberately:

<button type="submit">Save preferences</button>

<button type="button">Show password</button>

In ordinary form use, a button without an explicit type can act as a submit button. Use type="button" for controls that should not submit the form.

A native disabled button is generally removed from the keyboard tab order and cannot be activated normally. If an action is unavailable, explain why in visible text rather than relying only on its disabled appearance or a hover tooltip.

Why adding a role is not enough

This markup announces an intended role but does not create a complete button:

<div role="button">Save preferences</div>

Adding a click handler would still leave missing responsibilities. The implementation must address keyboard focus, Enter and Space activation, focus appearance, disabled behavior where relevant, and any required states. Adding tabindex="0" solves only the focusability portion.

Custom widgets are not forbidden. They carry implementation and testing obligations that must be owned deliberately. When a native element already does the job, letting native HTML do the work usually reduces both code and opportunities for inconsistency.

Align the visible label and accessible name

The visible label is the wording people see on or beside a control. The accessible name is the programmatically determined text that assistive technology uses to identify it.

For links and buttons, the accessible name commonly comes from the element’s contents. Depending on the markup, it can also come from image alternative text or an ARIA naming attribute. Other controls, such as form inputs, have their own labeling relationships.

Start with clear visible text that can also supply the name:

<a href="/inspection-checklist/">Aircraft inspection checklist</a>

<button type="submit">Save inspection notes</button>

Neither control needs an additional ARIA label. The visible wording already identifies its purpose.

Do not replace useful visible words with different hidden words

Consider this mismatch:

<button type="submit" aria-label="Find products">
  Search
</button>

The visible label is “Search,” but the accessible name is “Find products.” An aria-label generally replaces the name that would otherwise come from the button’s contents.

A sighted speech-input user may try to activate the button by saying the words they see. A conflicting programmatic name can make that interaction less reliable.

WCAG’s Label in Name guidance requires the accessible name to contain the visible text label for controls within its scope. Keeping the wording identical is often the simplest solution. When a longer name is necessary, keeping the visible wording intact at the beginning generally makes the relationship easier to follow.

<button type="submit">Search products</button>

For form fields and their associated labels, see accessible form design.

Make link purpose clear without adding unnecessary words

“Learn more” is not automatically a failure. A link’s purpose may be established by programmatically associated context, such as its containing paragraph. But repeated vague links can become difficult to distinguish when someone scans a page or navigates a list of links.

Prefer destination-oriented wording when it fits naturally:

  • “Review the warranty terms” instead of an isolated “Read more.”
  • “Download the inspection checklist (PDF)” instead of “Click here.”
  • “Compare window materials” instead of an unexplained “Explore.”

Where a compact visible label is necessary, additional accessible text can distinguish repeated controls:

<button type="button">
  Remove<span class="visually-hidden"> kitchen window estimate</span>
</button>

The resulting name is “Remove kitchen window estimate.” This preserves the visible word “Remove” while adding context. The example assumes a tested visually hidden CSS utility that leaves the text available to assistive technology—not display: none or the hidden attribute.

Hidden clarification does not help everyone. If the visible interface is ambiguous, improve its visible wording or layout first.

Make icon-only controls understandable

An icon-only control still needs a name. A magnifying glass, three dots, or a decorative glyph does not reliably communicate the same meaning to every person or tool.

When an icon-only design is appropriate, name the action rather than the picture:

<button type="button" aria-label="Close preview">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <path d="M6 6L18 18M18 6L6 18"
          fill="none" stroke="currentColor" stroke-width="2" />
  </svg>
</button>

“Close preview” describes the result. “X icon” describes the drawing. The SVG is hidden from assistive technology because the button already supplies the necessary name.

Also check that the control has:

  • A visible keyboard focus indicator.
  • A sufficiently large activation area and suitable spacing.
  • A programmatically exposed state when its meaning depends on state.
  • A visible explanation when the icon is not reliably understood.

WCAG 2.2’s AA Target Size (Minimum) criterion generally calls for targets of at least 24 by 24 CSS pixels or satisfaction of a specified exception, including a spacing exception. That is a conformance threshold, not a guarantee of comfortable use. Larger targets can be easier to operate.

Do not rely on a tooltip or title attribute as the only explanation. Hover is not available to everyone, and tooltip behavior varies. Visible text is often the clearer design.

Communicate state and result

A control’s name identifies it. Its state communicates conditions such as whether it is pressed, expanded, or unavailable. Those are related but distinct responsibilities.

A toggle can keep its name while its state changes

A formatting toggle can use a stable name and a changing pressed state:

<button type="button" aria-pressed="false">Bold</button>

When bold formatting becomes active, the implementation changes aria-pressed to true and updates the visual presentation. The name remains “Bold.”

This gives assistive technology a consistent identity with a changing state. Exact announcements depend on the browser, assistive technology, and user settings.

A disclosure can name the next available action

A disclosure button can expose whether its content is open:

<button type="button"
        aria-expanded="false"
        aria-controls="project-details">
  Show project details
</button>

<div id="project-details" hidden>
  <p>Project details appear here.</p>
</div>

The application must keep the content visibility and aria-expanded value synchronized. It may also change the label to “Hide project details” when the content opens. Alternatively, a stable label such as “Project details” can work with the expanded state.

aria-controls establishes a relationship; it does not open or close anything. Neither does aria-expanded. Behavior still needs implementation.

Focus and feedback complete the interaction

A correctly named button can still leave someone uncertain about what happened. Opening a dialog requires appropriate focus management. Closing it generally returns focus to its trigger or another logical location. Removing an item requires a sensible next focus position if the focused control disappears.

Saving data may also need confirmation beyond a color change. Depending on the interaction, a visible status message exposed appropriately to assistive technology can communicate the result without unnecessarily moving focus.

Test the control across input methods

Test the rendered interaction, not only the source code. Browser developer tools can expose a control’s computed accessible name, role, and states. Automated checks can find some missing information, but they cannot reliably decide whether a label describes the right action.

  1. Read the visible label. Can someone reasonably predict the destination or result?
  2. Inspect the accessible name and role. Do they agree with the visible wording and intended behavior?
  3. Use the keyboard. Confirm logical focus order, visible focus, and expected activation: Enter for links; Enter and Space for buttons.
  4. Use pointer and touch input. Check the activation area, spacing, and access to any explanations.
  5. Check speech-input naming. Can the words on screen identify the control? Where practical, test with a speech-input tool.
  6. Check assistive-technology output. Confirm that the name, role, and relevant states make sense in context.
  7. Complete the action. Verify the resulting focus position, state update, navigation, or feedback.

For a broader keyboard review, see keyboard navigation best practices.

A practical decision checklist

Before adding a link or button, answer five questions:

  1. Purpose: Is this navigation or an action?
  2. Element: Which native element provides the expected behavior?
  3. Visible wording: Does the label describe the destination or result?
  4. Accessible name: Does the computed name preserve the visible wording and provide enough context?
  5. Interaction: Do keyboard, pointer, touch, speech, and assistive-technology users encounter a coherent control?

The relevant standards provide complementary checks: WCAG’s Link Purpose (In Context), Headings and Labels, and Name, Role, Value guidance address different parts of that agreement. The WAI-ARIA Authoring Practices button and link patterns offer interaction guidance, not a replacement for native HTML.

The goal is not to add more accessibility attributes. It is to make the control understandable and dependable: the element establishes its role, the label explains its purpose, and the behavior fulfills that promise.