Tailwind CSS 50 🎨 Accessibility Utilities (sr-only, not-sr-only, forced-colors:, inert)
Accessibility is not a feature that can be added at the end. It is a property of the markup, the styles, and the interaction, and it must be designed from the start. Tailwind provides a small set of utilities and variants that address the most common accessibility needs: the sr-only and the not-sr-only for the content that must be available to the screen readers but not visible to the sighted users, the forced-colors: variant for the Windows High Contrast mode, and the inert variant for the non-interactive regions of the interface. The utilities are the tools, and the usage patterns are the discipline.
The sr-only utility visually hides an element while keeping it in the accessibility tree. The screen readers announce the content, and the sighted users do not see it. The utility is the standard for the icon buttons that need the text label, the skip links, the form labels that are visually implied, and the live regions that announce the dynamic updates. The not-sr-only undoes the hiding, and the combination with the responsive and the state variants produces the patterns: the label that is hidden on the small screens and shown on the large ones, the skip link that is hidden until it is focused .
The forced-colors: variant responds to the Windows High Contrast mode, where the operating system overrides the colors with the limited user-selected palette. The variant applies the semantic system colors — the Highlight, the HighlightText, the Canvas, the CanvasText — so the content stays readable in the high-contrast mode. The forced-color-adjust-none and the forced-color-adjust-auto utilities opt the elements in and out of the color enforcement .
The inert variant responds to the HTML inert attribute, which marks an element and its descendants as non-interactive and hides them from the assistive technologies. The variant applies the styles that signal the non-interactive state — the reduced opacity, the not-allowed cursor — so the sighted users understand which parts of the interface are disabled .
This chapter covers three areas. First, why the accessibility utilities exist — the visual-versus-assistive problem and the high-contrast problem. Second, the sr-only and the not-sr-only — the definition, the patterns, and the combination with the variants. Third, the forced-colors: and the inert — the high-contrast mode, the semantic system colors, and the non-interactive state. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the accessibility utilities.
Key point: The sr-only utility hides an element visually while keeping it available to the screen readers. The not-sr-only undoes it. The forced-colors: variant applies the styles in the Windows High Contrast mode, using the semantic system colors. The inert variant applies the styles when the element has the HTML inert attribute, signaling the non-interactive state. The utilities are the tools for the accessible markup, and the patterns are the discipline.
Why the accessibility utilities exist
The visual-versus-assistive problem. Some content is essential for the screen reader users but redundant for the sighted users. The icon button with the SVG has no visible text, and the screen reader needs the label. The form field with the placeholder has no visible label, and the screen reader needs the label. The skip link is invisible until it is focused, and the keyboard users need it. The sr-only utility solves the problem: the content is in the DOM, the screen readers announce it, and the sighted users do not see it .
The high-contrast problem. The Windows High Contrast mode overrides the colors with the limited user-selected palette. The backgrounds become the black or the white, the text becomes the contrasting color, and the custom brand colors are replaced. The content that relies on the color alone — the status indicator, the chart, the border — becomes unreadable. The forced-colors: variant and the semantic system colors solve the problem: the styles adapt to the high-contrast mode, and the content stays readable .
The non-interactive problem. The inert attribute marks the element and its descendants as non-interactive. The focus is prevented, the clicks are ignored, and the screen readers skip the region. The use cases are the modal that is open and the background that should be inactive, the off-screen menu, the disabled section. The inert variant applies the visual styles that signal the state, so the sighted users understand the region is not available .
The focus-indicator problem. The browsers provide the default focus outline, and the outline-none removes it. The removal is the accessibility problem: the keyboard users cannot see the focused element. The Tailwind v4 introduces the outline-hidden utility, which hides the default outline while preserving it in the forced colors mode. The fix is to apply the custom focus styles with the focus: variant when the default outline is removed .
The list-announcement problem. The Tailwind Preflight removes the list bullets and the numbers by default. The VoiceOver does not announce the unstyled lists as the lists. The role="list" attribute restores the announcement, and the pattern is the accessibility fix for the reset .
The trade-off. The accessibility utilities are the tools, and the usage requires the discipline. The sr-only content is invisible to the sighted users, and the developer must not hide the content that the sighted users need. The forced-colors: variant applies only in the high-contrast mode, and the developer must test the mode to verify the result. The inert attribute is the HTML feature, and the browser support is the modern. The trade-off is between the accessible markup and the extra effort, and the effort is the requirement for the production applications.
a. The sr-only and the not-sr-only
The sr-only utility hides an element visually while keeping it available to the screen readers.
<button>
<svg><!-- the icon --></svg>
<span class="sr-only">Settings</span>
</button>
The button has the icon for the sighted users and the sr-only text for the screen readers. The screen reader announces “Settings”, and the sighted user sees the icon .
The not-sr-only undo. The not-sr-only utility makes the element visible again.
<span class="sr-only sm:not-sr-only">Settings</span>
The label is hidden on the small screens and shown on the sm breakpoint and above. The pattern is the responsive label that is the icon-only on the mobile and the full label on the desktop .
The focus pattern. The focus:not-sr-only makes the element visible when it is focused. The pattern is the skip link.
<a href="#content" class="sr-only focus:not-sr-only">
Skip to content
</a>
The link is hidden until the keyboard user tabs to it, and then it becomes visible. The pattern is the standard for the skip links, and it is the accessibility requirement for the keyboard navigation .
The live-region pattern. The sr-only is the container for the live region that announces the dynamic updates.
<div aria-live="polite" class="sr-only">
<p>3 new notifications</p>
</div>
The screen reader announces the update when the content changes, and the sighted users do not see the container .
The label pattern. The sr-only label is the accessible name for the icon button.
<button aria-label="Close dialog" class="p-2">
<svg><!-- the X icon --></svg>
</button>
The aria-label is the alternative, and the sr-only span is the other option. The two are the equivalent, and the choice is the preference .
b. The forced-colors: variant
The forced-colors: variant applies the styles when the Windows High Contrast mode is active. The variant is used with the semantic system colors.
<button class="bg-blue-500 forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]">
Submit
</button>
The button has the blue background in the normal mode and the Highlight system color in the forced-colors mode. The Highlight and the HighlightText are the semantic system colors that the operating system provides .
The forced-color-adjust utilities. The forced-color-adjust-none opts the element out of the forced colors, and the forced-color-adjust-auto restores the enforcement.
<fieldset class="forced-color-adjust-none lg:forced-color-adjust-auto">
<!-- the form -->
</fieldset>
The form opts out on the small screens and restores the enforcement on the lg breakpoint. The pattern is the useful when the forced colors degrade the usability .
The semantic system colors. The list of the semantic system colors includes the Canvas, the CanvasText, the LinkText, the Highlight, the HighlightText, the ButtonFace, the ButtonText, the GrayText, and the others. The colors are the user-selected, and they adapt to the high-contrast theme .
c. The inert variant
The inert variant applies the styles when the element has the HTML inert attribute. The attribute marks the element and the descendants as non-interactive and hidden from the assistive technologies.
<div inert class="opacity-100 inert:opacity-50">
<!-- the content -->
</div>
<button inert class="cursor-pointer inert:cursor-not-allowed">
The button
</button>
The div has the full opacity normally and the reduced opacity when the inert attribute is present. The button has the pointer cursor normally and the not-allowed cursor when the inert attribute is present. The visual cues signal the non-interactive state .
The combination with the other variants. The inert variant combines with the responsive and the state variants.
<div class="md:inert:opacity-75">
<!-- the reduced opacity on the md and above when inert -->
</div>
The pattern is the responsive and the state-specific styling for the non-interactive region .
The use case. The inert attribute is the modern HTML feature for the modal background, the off-screen menu, and the disabled section. The inert variant provides the visual styles, and the attribute provides the behavior. The two work together.
Complete Example Session
<!-- ============================================
PART 1: THE SR-ONLY ICON BUTTON
============================================ -->
<button>
<svg class="h-5 w-5" fill="none" stroke="currentColor">
<path d="M6 18L18 6M6 6l12 12" />
</svg>
<span class="sr-only">Close dialog</span>
</button>
<!-- ============================================
PART 2: THE RESPONSIVE LABEL
============================================ -->
<button>
<svg><!-- the icon --></svg>
<span class="sr-only sm:not-sr-only">Settings</span>
</button>
<!-- The label is hidden on the mobile and shown on the sm and above. -->
<!-- ============================================
PART 3: THE SKIP LINK
============================================ -->
<a href="#content" class="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-4 focus:z-50 focus:rounded focus:bg-white focus:p-4">
Skip to content
</a>
<!-- The link is hidden until the keyboard user focuses it. -->
<!-- ============================================
PART 4: THE LIVE REGION
============================================ -->
<div aria-live="polite" class="sr-only">
<p>3 new notifications</p>
</div>
<!-- The screen reader announces the update. -->
<!-- ============================================
PART 5: THE ARIA LABEL ALTERNATIVE
============================================ -->
<button aria-label="Close dialog" class="p-2">
<svg class="h-5 w-5"><!-- the X icon --></svg>
</button>
<!-- The aria-label is the alternative to the sr-only span. -->
<!-- ============================================
PART 6: THE FORCED-COLORS BUTTON
============================================ -->
<button class="bg-blue-500 text-white forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]">
Submit
</button>
<!-- The button uses the system colors in the forced-colors mode. -->
<!-- ============================================
PART 7: THE FORCED-COLOR-ADJUST
============================================ -->
<fieldset class="forced-color-adjust-none lg:forced-color-adjust-auto">
<legend>Choose a color:</legend>
<select class="hidden lg:block">
<option>White</option>
<option>Gray</option>
<option>Black</option>
</select>
</fieldset>
<!-- The form opts out on the small screens and restores on the lg. -->
<!-- ============================================
PART 8: THE INERT REGION
============================================ -->
<div inert class="opacity-100 inert:opacity-50">
<p>The content is non-interactive.</p>
</div>
<button inert class="cursor-pointer inert:cursor-not-allowed">
The button
</button>
<!-- The visual cues signal the non-interactive state. -->
<!-- ============================================
PART 9: THE INERT WITH THE VARIANTS
============================================ -->
<div class="md:inert:opacity-75">
<!-- The reduced opacity on the md and above when inert. -->
</div>
<!-- ============================================
PART 10: THE COMPLETE ACCESSIBLE FORM
============================================ -->
<form>
<div>
<label for="email" class="block text-sm font-medium">Email</label>
<input
id="email"
type="email"
class="mt-1 w-full rounded-md border-gray-300"
aria-describedby="email-help"
/>
<p id="email-help" class="sr-only">
We will never share your email with anyone.
</p>
</div>
<div class="mt-4">
<label for="password" class="block text-sm font-medium">Password</label>
<input
id="password"
type="password"
class="mt-1 w-full rounded-md border-gray-300"
/>
</div>
<button
type="submit"
class="mt-6 bg-blue-500 text-white forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]"
>
Submit
</button>
</form>
The ten parts show the sr-only icon button, the responsive label, the skip link, the live region, the aria-label alternative, the forced-colors button, the forced-color-adjust, the inert region, the inert with the variants, and the complete accessible form.
Quick Reference
The Screen Reader Utilities
| Utility | Effect |
|---|---|
sr-only | Visually hidden, available to the screen readers |
not-sr-only | Undoes the sr-only |
focus:not-sr-only | The skip link pattern |
sm:not-sr-only | The responsive label |
The Forced Colors Utilities
| Utility | Effect |
|---|---|
forced-colors: | Applies in the high-contrast mode |
forced-color-adjust-none | Opts out of the forced colors |
forced-color-adjust-auto | Restores the enforcement |
The Semantic System Colors
| Color | Use |
|---|---|
Highlight | The selected item background |
HighlightText | The selected item text |
Canvas | The background |
CanvasText | The text |
LinkText | The links |
ButtonFace | The button background |
ButtonText | The button text |
GrayText | The disabled text |
The Inert Variant
| Utility | Effect |
|---|---|
inert: | Applies when the inert attribute is present |
inert:opacity-50 | The reduced opacity |
inert:cursor-not-allowed | The not-allowed cursor |
md:inert:opacity-75 | The responsive and the state |
The Accessibility Checklist
| The item | The utility |
|---|---|
| The icon button label | sr-only |
| The skip link | sr-only focus:not-sr-only |
| The live region | sr-only with aria-live |
| The high-contrast mode | forced-colors: |
| The non-interactive region | inert |
Best Practices
✅ Do This:
<!-- Use the sr-only for the icon button labels -->
<button><svg /><span class="sr-only">Settings</span></button> <!-- ✅ -->
<!-- Use the focus:not-sr-only for the skip links -->
<a href="#content" class="sr-only focus:not-sr-only">Skip</a> <!-- ✅ -->
<!-- Use the not-sr-only for the responsive labels -->
<span class="sr-only sm:not-sr-only">Settings</span> <!-- ✅ -->
<!-- Use the forced-colors for the high-contrast mode -->
<button class="forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]"> <!-- ✅ -->
<!-- Use the inert for the non-interactive regions -->
<div inert class="inert:opacity-50"> <!-- ✅ -->
<!-- Use the aria-label as the alternative -->
<button aria-label="Close">...</button> <!-- ✅ -->
<!-- Use the role="list" for the unstyled lists -->
<ul role="list">...</ul> <!-- ✅ -->
❌ Don’t Do This:
<!-- Don't use the sr-only for the content the sighted users need -->
<span class="sr-only">Important message</span> <!-- the users cannot see it --> // ❌
<!-- Don't remove the outline without the replacement -->
<button class="outline-none"> <!-- the keyboard users cannot see the focus --> // ❌
<!-- Don't rely on the color alone -->
<span class="text-green-500">Success</span> <!-- the color-blind users --> // ❌
<!-- Don't forget the forced-colors -->
<button class="bg-blue-500"> <!-- the high-contrast mode --> // ❌
<!-- Don't use the inert without the visual cue -->
<div inert> <!-- the users do not know it is non-interactive --> // ❌
<!-- Don't use the aria-label on the non-interactive elements -->
<div aria-label="..."> <!-- the div is not the interactive --> // ❌
Common Pitfalls
| The pitfall | The why | The fix |
|---|---|---|
| The screen reader does not announce the icon | The missing sr-only label | Add the sr-only span |
| The skip link is invisible | The sr-only without the focus:not-sr-only | Add the focus variant |
| The label is hidden on the desktop | The sr-only without the not-sr-only | Use the sm:not-sr-only |
| The high-contrast mode is broken | The missing forced-colors: | Add the variant |
The inert region has no cue | The missing inert: styles | Add the opacity or the cursor |
| The unstyled list is not announced | The Preflight removes the markers | Add the role="list" |
| The focus outline is missing | The outline-none without the replacement | Use the outline-hidden or add the custom focus |
Real-World Examples
1. The Icon Button
<button><svg /><span class="sr-only">Close</span></button>
2. The Skip Link
<a href="#content" class="sr-only focus:not-sr-only">Skip to content</a>
3. The Responsive Label
<span class="sr-only sm:not-sr-only">Settings</span>
4. The Live Region
<div aria-live="polite" class="sr-only"><p>Update</p></div>
5. The Forced Colors
<button class="forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]">
6. The Forced Color Adjust
<fieldset class="forced-color-adjust-none lg:forced-color-adjust-auto">
7. The Inert Region
<div inert class="inert:opacity-50">
8. The Inert Cursor
<button inert class="inert:cursor-not-allowed">
9. The ARIA Label
<button aria-label="Close">...</button>
10. The Accessible Form
<label for="email">Email</label>
<input id="email" aria-describedby="email-help" />
<p id="email-help" class="sr-only">...</p>
Visual
The sr-only Utility
┌──────────────────────────────────────────────────────────────┐
│ THE sr-only UTILITY │
│ │
│ <button> │
│ <svg> ← the sighted users see the icon │
│ <span class="sr-only">Settings</span> ← the screen readers│
│ </button> │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ The element is positioned off-screen: │ │
│ │ position: absolute; │ │
│ │ width: 1px; height: 1px; │ │
│ │ overflow: hidden; │ │
│ │ clip: rect(0, 0, 0, 0); │ │
│ │ │ │
│ │ The screen reader reads the content. │ │
│ │ The sighted user does not see it. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
The Skip Link
┌──────────────────────────────────────────────────────────────┐
│ THE SKIP LINK │
│ │
│ <a href="#content" class="sr-only focus:not-sr-only"> │
│ Skip to content │
│ </a> │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ The link is INVISIBLE normally. │ │
│ │ │ │
│ │ When the keyboard user tabs to it: │ │
│ │ The focus:not-sr-only applies. │ │
│ │ The link becomes VISIBLE. │ │
│ │ │ │
│ │ The user presses the Enter, and the page jumps │ │
│ │ to the #content. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
The Forced Colors
┌──────────────────────────────────────────────────────────────┐
│ THE FORCED COLORS │
│ │
│ THE NORMAL MODE: │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ <button class="bg-blue-500 text-white"> │ │
│ │ → the blue background, the white text │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ THE HIGH-CONTRAST MODE: │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ <button class="forced-colors:bg-[Highlight] │ │
│ │ forced-colors:text-[HighlightText]"> │ │
│ │ → the system Highlight background │ │
│ │ → the system HighlightText text │ │
│ │ │ │
│ │ The content stays readable in the high contrast. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
The Inert Variant
┌──────────────────────────────────────────────────────────────┐
│ THE INERT VARIANT │
│ │
│ <div inert class="opacity-100 inert:opacity-50"> │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ WITHOUT the inert attribute: │ │
│ │ → the opacity is 100% │ │
│ │ → the element is interactive │ │
│ │ │ │
│ │ WITH the inert attribute: │ │
│ │ → the opacity is 50% │ │
│ │ → the element is non-interactive │ │
│ │ → the screen readers skip it │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ The visual cue matches the actual state. │
│ │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
sr-only | Visually hidden, screen-reader available |
not-sr-only | Undoes the sr-only |
focus:not-sr-only | The skip link pattern |
forced-colors: | The Windows High Contrast mode |
forced-color-adjust-none | Opts out of the forced colors |
inert: | The non-interactive state |
| The semantic colors | Highlight, HighlightText, Canvas, CanvasText |
The role="list" | The list announcement |
The outline-hidden | Hides the outline, preserves the forced colors |
Key takeaways:
- The
sr-onlyutility hides an element visually while keeping it available to the screen readers. The utility is the standard for the icon button labels, the skip links, the live regions, and the form labels that are visually implied . - The
not-sr-onlyundoes thesr-only. The combination with the responsive variants produces the patterns: the label that is hidden on the mobile and shown on the desktop. Thefocus:not-sr-onlymakes the skip link visible when it is focused . - The
forced-colors:variant applies the styles in the Windows High Contrast mode. The variant uses the semantic system colors — theHighlight, theHighlightText, theCanvas, theCanvasText— so the content stays readable. Theforced-color-adjust-noneopts the element out of the enforcement . - The
inertvariant applies the styles when the element has the HTMLinertattribute. The attribute marks the element and the descendants as non-interactive and hides them from the assistive technologies. The variant applies the visual cues — the reduced opacity, the not-allowed cursor . - The
outline-hiddenutility hides the default outline while preserving it in the forced colors mode. Theoutline-noneremoves the outline completely. When the outline is removed, the custom focus styles must be applied with thefocus:variant . - The Preflight removes the list bullets and the numbers, and the
role="list"restores the announcement. The VoiceOver does not announce the unstyled lists as the lists, and therole="list"is the fix . - The
aria-labelis the alternative to thesr-onlyspan. The two provide the accessible name for the icon buttons, and the choice is the preference . - The accessibility utilities are the tools, and the discipline is the requirement. The
sr-onlycontent must be the content the sighted users do not need. Theforced-colors:must be tested in the high-contrast mode. Theinertregion must have the visual cue. The result is the accessible interface, which is the foundation of the inclusive web.
Remember: The accessibility utilities are the small set of the tools that address the common needs. The sr-only and the not-sr-only handle the content that is for the screen readers only. The forced-colors: handles the Windows High Contrast mode. The inert handles the non-interactive regions. The outline-hidden preserves the focus in the forced colors mode. The role="list" restores the list announcement. The result is the markup that works for every user, which is the foundation of the accessible web.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!