VisuallyHidden

Hide content visually while keeping it accessible to screen readers.

VisuallyHidden

The VisuallyHidden component hides content from sighted users while keeping it fully accessible to screen readers and assistive technologies. Use it for accessible labels, descriptions, and context that sighted users don't need to see.

VisuallyHidden uses industry-standard CSS that clips content to 1×1px and removes it from visual flow, while remaining accessible in the DOM.


Features

  • Content hidden from sighted users
  • Fully accessible to screen readers and AT
  • No layout impact (doesn't shift other elements)
  • Works with any inline content
  • Preserves content for localization and copy-paste

Usage

import { VisuallyHidden } from '@loke/ui/visually-hidden';

export default function Example() {
  return (
    <button type="button">
      <VisuallyHidden>Save the file</VisuallyHidden>
      <span aria-hidden>💾</span>
    </button>
  );
}

Props

Prop

Type


Examples

No visible label — screen readers announce "Delete item"

Input has no visible label — the hidden "Search" label is read by screen readers

Icon button with hidden label

<button type="button">
  <VisuallyHidden>Delete item</VisuallyHidden>
  <span aria-hidden="true">🗑️</span>
</button>

Hidden label for input

<label htmlFor="email">
  <VisuallyHidden>Email address</VisuallyHidden>
</label>
<input id="email" type="email" placeholder="email@example.com" />

Additional context for button

<button type="button">
  Subscribe
  <VisuallyHidden>to our weekly newsletter</VisuallyHidden>
</button>

Multi-part accessible name

<div>
  <span>Status:</span>
  <span className="font-bold">Active</span>
  <VisuallyHidden>(Last updated 2 hours ago)</VisuallyHidden>
</div>

CSS Implementation

VisuallyHidden applies these styles:

border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
word-wrap: normal;

This approach:

  • Removes element from visual flow (position: absolute, width/height: 1px)
  • Clips content to prevent any visibility (clip)
  • Hides overflow and prevents wrapping (overflow, white-space)
  • Keeps element in the DOM and accessibility tree

Accessibility

VisuallyHidden is one of the most important accessibility tools:

  • Screen readers announce content normally
  • Keyboard navigation includes only focusable elements; hidden text itself is not focusable unless explicitly made focusable
  • Content is available to all assistive technologies
  • Doesn't remove content from DOM or accessibility tree (unlike display: none or aria-hidden)

Common Patterns

Icon-only buttons

Always provide an accessible label:

// Good: visible text
<button>Download</button>

// Good: hidden text with icon
<button>
  <VisuallyHidden>Download</VisuallyHidden>
  <DownloadIcon />
</button>

// Acceptable: aria-label (but hidden text is preferred for i18n)
<button aria-label="Download">
  <DownloadIcon />
</button>

Form labels

Always label inputs:

// Good: visible label
<label htmlFor="name">Name</label>
<input id="name" />

// Good: hidden label (e.g., when label is implied visually)
<label htmlFor="search">
  <VisuallyHidden>Search</VisuallyHidden>
</label>
<input id="search" placeholder="Search..." />

Duplicate content

Don't hide content that's critical to understanding:

// Bad: hiding essential context
<button>
  <VisuallyHidden>View all orders</VisuallyHidden>
  See more
</button>

// Good: essential info is visible; extra context is hidden
<button>
  See more orders
  <VisuallyHidden>(5 new orders pending)</VisuallyHidden>
</button>

Best practices

  • Use for labels, descriptions, and context that aren't visually obvious
  • Keep hidden text short and meaningful (not redundant)
  • Pair with aria-hidden="true" on decorative elements to avoid duplication
  • Test with a screen reader to ensure content is announced
  • Avoid hiding large blocks of content; VisuallyHidden is for concise labels and context
  • Consider localization: hidden text still needs translation
  • Remember that hidden text can be selected and copied; write it clearly

Alternatives

  • aria-label: Good for very short labels, less flexible
  • aria-labelledby: Links to visible text as accessible name
  • aria-describedby: Links to description (not the accessible name)
  • <legend>: For form fieldsets
  • Visible labels: Always prefer visible text when possible

VisuallyHidden is best for labels that are implied visually but need to be explicit for AT users.