Noctis

Buttons trigger an action — submitting a form, opening a dialog, confirming a choice. Built on Base UI, with an emphasis level for every job and full keyboard and screen-reader support.

Variants

Nine emphasis levels. Use one neutral-white primary per view, reach for accent when a second action needs weight, and let secondary, outline, and ghost carry the rest; danger is reserved for destructive actions, with ghost-danger its low-emphasis twin — a transparent ghost weight painted in the danger tone for an inline destructive action like "Sign out everywhere", where the wash deepens from hover to active and the focus ring stays danger-coloured so the intent survives interaction; and link sits inline with text — with link-foreground its quieter twin, painting the foreground colour for inline links on dark or accent surfaces where the accent blue would disappear.

Sizes

Four heights — extra-small through large — sharing one type and spacing rhythm.

With icons

Pair a leading or trailing glyph with the label. Icons are decorative; the label names the action.

Icon only

Square the button for a lone glyph. Always pass an aria-label — without visible text, assistive technology needs it to announce the action.

Loading

A loading button shows a centered spinner, blocks interaction, and keeps its size so the layout never jumps.

Disabled

A disabled button dims to the disabled opacity and ignores interaction.

Full width

Stretch the button to fill its container — common in narrow forms and on mobile.

For navigation, style a link with buttonVariants so it stays a real anchor while wearing the button's look; use the Button itself for in-place actions.

Theme scope

ThemeScope re-tunes a whole region's shape — corner radius, density, and type scale — through the cascade, with no per-button prop and without touching the app-wide theme. Tweak the knobs below and watch every button inside the scope retune together; surfaces stay capped, so a pill radius rounds the controls without ballooning cards. See Customization for nesting, reset, and the portal caveat.

On surfaces

The same control re-tuned across the elevation scopes — the root canvas, an elevated panel, a menu, and a sunken well. It stays legible on every layer.

root
elevated
menu
sunken

Design tokens

Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every button in that region retunes — e.g. .marketing { --noctis-button-border-radius: 9999px; } pills every button beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.

Token

API reference

Generated from the component's types — every prop, type, default, and description comes straight from the source. Button extends the Base UI Button props, so nativeButton and the native button attributes pass straight through; expand a row for the full type and description.

Prop

AttributeDescription
data-slotThe catalog slot that marks the rendered element as a Button for SLOTS.md and testing hooks.
data-buttonThe stable styling marker every `button.css` rule keys off — always present, independent of `data-slot`.
data-variantThe visual emphasis — `primary` | `accent` | `secondary` | `outline` | `ghost` | `ghost-danger` | `danger` | `link` | `link-foreground`.
data-sizeThe size scale — `xs` | `sm` | `md` | `lg`; the generated layer keys the per-size internals off it.
data-icon-onlyPresent (`true`) when the button is squared for a single icon.
data-full-widthPresent (`true`) when the button stretches to its container's width.
data-loadingPresent (`true`) while loading — hides the content row in place behind the spinner overlay.
data-disabledPresent when the button is disabled (including while `loading`).