Utilities

Single-purpose classes

Utilities handle the cases that don't earn their own component or token override: set text alignment on one element, nudge a gap to a specific size, hide something on mobile. Each utility does exactly one thing. They live in the utilities cascade layer, so they win over lower layers without !important.

Brio is not a utility framework. The catalog below is deliberately narrow and will stay that way: if you find yourself wanting more, first check whether a token override, composition primitive, or component handles it. Only reach for a utility when those don't.

The class tables below are pulled from src/css/utilities.css via brio cssref, so they stay in sync with the source. The two single-utility sections (.visually-hidden and .link-plain) are described in prose because their behavior doesn't fit a one-line table cell.

Visibility

  • .visually-hidden -- hide from the visual UI while remaining in the accessibility tree. Use for skip links, form labels that the design doesn't show, and screen-reader-only text. Not the same as [hidden] (which removes the element from the a11y tree too).

Text

Alignment

Logical-property values so RTL writing modes flip correctly.

ClassDescription
.text-startAlign text to the inline-start edge
.text-centerCenter text
.text-endAlign text to the inline-end edge

Color

Maps to semantic color tokens. Keep these minimal; component-scoped tokens are usually the right override point instead.

ClassDescription
.text-mutedMuted secondary text
.text-subtleSubtle de-emphasized text
.text-inverseInverted text for dark surfaces
.text-primaryPrimary brand color
.text-normalReverts to the default --color-text
.text-accentAccent color
.text-successSuccess status color
.text-warningWarning status color
.text-dangerDanger status color

Family and case

ClassDescription
.text-monoSwitch to the monospace family
.text-uppercaseTransform to uppercase
.text-lowercaseTransform to lowercase

Size

Keyed to the fluid type scale. See the type scale on the Tokens page for the resolved sizes at each breakpoint.

ClassDescription
.text--2Smallest caption size
.text--1Step below body
.text-0Body baseline
.text-1One step above body
.text-2Subheading
.text-3Heading
.text-4Large heading
.text-5Display size

See Tokens -- Type scale for the resolved sizes at each breakpoint.

Weight

ClassDescription
.text-thinThin (100)
.text-extralightExtra light (200)
.text-lightLight (300)
.text-normalNormal (400)
.text-mediumMedium (500)
.text-semiboldSemibold (600)
.text-boldBold (700)
.text-blackBlack (900)

Line height

ClassDescription
.leading-tightTight leading for labels
.leading-headingDefault heading leading
.leading-bodyDefault body leading
.leading-looseLoose leading for emphasis contexts
  • .link-plain -- remove underline and use --color-text. For logo links, breadcrumb home, and similar cases where the anchor is chrome rather than prose.

Spacing

Gap

Set the gap property directly, keyed to the raw --space-* scale. Use when you want an explicit size on a flex or grid container.

ClassDescription
.gap-3xsgap: var(--space-3xs)
.gap-2xsgap: var(--space-2xs)
.gap-xsgap: var(--space-xs)
.gap-smgap: var(--space-sm)
.gap-mdgap: var(--space-md)
.gap-lggap: var(--space-lg)
.gap-xlgap: var(--space-xl)
.gap-2xlgap: var(--space-2xl)

For density-aligned gaps (inside .stack, .cluster, or a component), prefer the .is-snug / .is-tight modifiers the composition primitive provides, or override --stack-gap / --cluster-gap with a --gap-* alias from the density grammar. The raw .gap-* utilities are for deliberate one-off sizing.

Flow space

Set --flow-space at the --space-* scale. Apply to a .flow container to set its rhythm, or to an individual child to tune the gap above just that element.

ClassDescription
.flow-space-none--flow-space: 0
.flow-space-3xs--flow-space: var(--space-3xs)
.flow-space-2xs--flow-space: var(--space-2xs)
.flow-space-xs--flow-space: var(--space-xs)
.flow-space-sm--flow-space: var(--space-sm)
.flow-space-md--flow-space: var(--space-md)
.flow-space-lg--flow-space: var(--space-lg)
.flow-space-xl--flow-space: var(--space-xl)
.flow-space-2xl--flow-space: var(--space-2xl)
.flow-space-3xl--flow-space: var(--space-3xl)

Apply .flow-space-* to a .flow container to set its rhythm, or to an individual child to tune the gap above just that element (see the Flow per-child override pattern).

Responsive visibility

Viewport

Hide elements based on viewport width. Breakpoints: sm 40rem, md 48rem, lg 64rem.

ClassDescription
.hide-below-smHidden below the sm breakpoint
.hide-below-mdHidden below the md breakpoint
.hide-below-lgHidden below the lg breakpoint
.hide-above-smHidden at the sm breakpoint and above
.hide-above-mdHidden at the md breakpoint and above
.hide-above-lgHidden at the lg breakpoint and above

Breakpoints match the breakpoints reference. Pair them for mobile-swap-desktop patterns: .hide-above-md on the hamburger button, .hide-below-md on the nav. The hamburger shows below the breakpoint; the nav shows at and above.

Container queries

Opt a parent into container queries with .cq-inline, then use .cq-hide-* on its descendants to respond to the container's inline size instead of the viewport.

ClassDescription
.cq-inlineOpt into inline-size container queries
.cq-hide-below-smHidden when the container is below sm
.cq-hide-below-mdHidden when the container is below md
.cq-hide-below-lgHidden when the container is below lg
.cq-hide-above-smHidden when the container is sm or wider
.cq-hide-above-mdHidden when the container is md or wider
.cq-hide-above-lgHidden when the container is lg or wider

Use container queries when you want responsive behavior based on a container's width instead of the viewport -- useful for widgets that appear in contexts of varying width (sidebar vs main, card grid vs full width, etc.).

Drag the right edge to cross the md breakpoint and see the utilities swap:

This is a query container.

I hide when the container is under 48rem (md).

I hide when the container is 48rem or wider.

<docs-resize>
    <div class="cq-inline">
        <p>This is a query container.</p>
        <p class="cq-hide-below-md text-success">I hide when the container is under 48rem (md).</p>
        <p class="cq-hide-above-md text-danger">I hide when the container is 48rem or wider.</p>
    </div>
</docs-resize>

Container-query breakpoints match the viewport breakpoints so the vocabulary stays consistent. The difference is what the breakpoint resolves against -- the container's width for .cq-*, the viewport for .hide-*.