Helpers
Helpers are the few classes that are not part of a utility family: sr-only, which hides content visually but keeps it available to screen readers, and the breakpoint debugger, an optional overlay that shows the current screen size while you build a layout.
How helpers work
Section titled “How helpers work”Neither helper is a utility class, so $generate-utility-classes does not control them. Each has its own switch:
| Helper | Source | Emitted when | Default |
|---|---|---|---|
.sr-only |
Base layer (base/_base.scss, inside @layer base) |
The base feature flag is on |
On |
.NuvoUI-Debugger-Wrapper and its parts |
utilities/_helpers.scss |
$enable-debugger is true |
Off |
| Setting | .sr-only |
Debugger |
|---|---|---|
$generate-utility-classes: false |
Emitted | Emitted if $enable-debugger is true |
$feature-flags: ("base": false) |
Not emitted | Not affected |
$enable-debugger: false |
Not affected | Not emitted |
$parent-selector: ".app" |
.app .sr-only |
Not prefixed: .NuvoUI-Debugger-Wrapper |
Neither helper has a mixin, a responsive variant or a token.
Screen reader only
Section titled “Screen reader only”sr-only removes an element from the visual layout but leaves it in the accessibility tree, so screen readers still announce it. Use it for text that the visual design expresses another way: the label of an icon button, a heading that sighted users infer from the layout, or extra context on a repeated link such as “Read more”.
<div class="flex x-center gap-3"> <button type="button"> <span aria-hidden="true">X</span> <span class="sr-only">Close dialog</span> </button> <a href="#">Read more<span class="sr-only"> about backdrop filters</span></a></div>The class is emitted in the base layer together with the element styles:
@layer base { .sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip-path: inset(50%) !important; white-space: nowrap !important; border: 0 !important; }}Every declaration is !important. An important declaration inside a cascade layer outranks unlayered styles, including unlayered !important ones, so no utility class on the same element can reveal the content by accident. The same rule also means you cannot undo sr-only with another class: remove the class instead.
sr-only is described alongside the other ways of hiding content on the Display page, which compares it with hide, hidden and invisible.
Choosing a hiding method
Section titled “Choosing a hiding method”| You want | Use |
|---|---|
| Hidden visually, announced by screen readers | sr-only |
| Hidden for everyone, no space taken | hide or hidden |
| Hidden for everyone, space kept | invisible |
| Visible, not announced (decorative) | aria-hidden="true" on the element, no class |
Skip links and other focusable content
Section titled “Skip links and other focusable content”Do not put sr-only on a link or control that should appear when it receives focus, such as a “Skip to content” link: the !important declarations keep it one pixel wide even while focused. Write a dedicated class that hides the element only while it is not focused:
.skip-link { @include apply(absolute, p(2), bg(surface), rounded); inset-inline-start: token(space-2); inset-block-start: token(space-2);
&:not(:focus-visible) { clip-path: inset(50%); width: 1px; height: 1px; overflow: hidden; white-space: nowrap; }}Without the base layer
Section titled “Without the base layer”With $feature-flags: ("base": false) core emits no base element styles and no sr-only class. There is no sr-only mixin, so apply(sr-only) raises Mixin not found: sr-only. Copy the declarations above into your own class when the base layer is off.
// error.label { @include apply(sr-only);}Breakpoint debugger
Section titled “Breakpoint debugger”The debugger is a small fixed overlay that names the current screen range, for use during development. Core ships only its CSS; it has no script and creates no markup. Turn it on when loading core:
@use "@nuvoui/core" with ( $enable-debugger: true);Then add the overlay to your page yourself:
<div class="NuvoUI-Debugger-Wrapper top-right"> <div class="NuvoUI-Debugger-Main" data-size="1180 x 720"></div> <div class="NuvoUI-Debugger" data-element=".sidebar" data-size="280 x 720"></div> <span class="NuvoUI-Debugger-Close">x</span></div>| Part | What it shows or does |
|---|---|
.NuvoUI-Debugger-Wrapper |
Fixed container, z-index: 999999, ignores pointer events. Top left by default. |
top-left, top-right, bottom-left, bottom-right |
Position modifiers on the wrapper, 10px from the corner |
.NuvoUI-Debugger-Main |
The screen label (Screen: md) from media queries, then the data-size attribute |
.NuvoUI-Debugger |
One extra panel per element you want to watch: data-element in bold, then data-size |
.NuvoUI-Debugger-Close |
A round button in the top right corner of the wrapper; it is the only part that accepts clicks |
data-size and data-element are plain attributes shown through attr(). Keep them current from your own script, for example with a resize listener or a ResizeObserver, and hide the wrapper when the close button is clicked.
Screen label ranges
Section titled “Screen label ranges”The label is generated from $breakpoints. Each label names the breakpoint that the viewport has not reached yet, so it is one step ahead of the responsive suffixes that are active:
| Viewport width (default breakpoints) | Label | Active responsive suffixes |
|---|---|---|
| Up to 480px | Screen: xs |
none (@xs from exactly 480px) |
| 480px to 639.98px | Screen: sm |
@xs |
| 640px to 767.98px | Screen: md |
@xs, @sm |
| 768px to 1023.98px | Screen: lg |
up to @md |
| 1024px to 1279.98px | Screen: xl |
up to @lg |
| 1280px to 1535.98px | Screen: 2xl |
up to @xl |
| 1536px and wider | No label | up to @2xl |
At exactly 480px both the xs and the sm query match and the later one, sm, is shown.
Accessibility preference mixins
Section titled “Accessibility preference mixins”The mixins that react to user preferences, reduced-motion, high-contrast, prefers-dark and dark-mode, live in the accessibility tools module. They are documented on the Media queries page and, for the dark theme, on the Theming page.
Accessibility and RTL
Section titled “Accessibility and RTL”- Keep the text meaningful.
sr-onlytext is read in place, so write it to make sense in the surrounding sentence (“Read more about backdrop filters”), and keep a leading space where it continues visible text. - Do not hide focusable controls with
sr-only. A keyboard user can tab to a control they cannot see. Use the skip link pattern above for controls that should appear on focus. - Prefer real labels. For form controls, a visible
labelis better for everyone; usesr-onlyon alabelonly when the design has no room for it. - RTL.
sr-onlydoes not depend on text direction. The debugger position modifiers are physical (top-leftstays on the left in right-to-left pages).