Button
Buttons are the primary way to trigger actions in an interface.
Components · Actions
Buttons are the primary way to trigger actions in an interface. Namirial buttons are built from --nm-button-* tokens defined in namirial-theme.css, and ship in seven intents, two styles, and five sizes — geometry (height, padding, radius, gap) is baked into the size modifier classes.
Overview
A button invokes an action. Every button should communicate three things at a glance: that it is clickable, what it will do, and how important the action is relative to its neighbors. Use intent to set the action's weight, size to match its container, and style (solid vs. ghost) to control how loudly it sits on the page.
When to use
- To commit a change or submit a form (
Save,Create,Sign document) - To advance a user through a flow (
Continue,Next step) - To trigger an immediate, self-contained action (
Send,Download,Copy link)
When not to use
- For navigation between pages — use a link instead. Buttons do things; links go places.
- To toggle a setting on or off — use a switch or checkbox.
- For a choice between a small set of options — use a segmented control.
Anatomy
A button is a single focusable element: a label framed by geometry, with optional icons flanking the label. Color properties (fill, border, label) are driven by --nm-button-* custom properties. Geometry (height, padding, gap, radius) is baked directly into the size modifier classes (nm-button--xs through nm-button--xl).
Tokens and values that drive each part
| Part | Role | Source |
|---|---|---|
| Container | Fill | --nm-button-{intent}-default-bg |
| Container | Horizontal padding | padding-inline — 8 / 12 / 16 / 24 / 24 px (xs → xl) |
| Container | Height | height — 24 / 32 / 40 / 48 / 56 px (xs → xl) |
| Container | Radius | border-radius — 6 / 8 / 10 / 12 / 12 px (xs → xl) |
| Border | Color | --nm-button-{intent}-default-border |
| Border | Width | border-width: 1px (fixed) |
| Label | Color (solid) | --nm-button-{intent}-fg |
| Label | Color (ghost) | --nm-button-ghost-{intent}-fg |
| Label | Size | font-size — 12 / 14 / 16 / 20 / 24 px (xs → xl) |
| Icons | Gap | gap — 8 / 8 / 12 / 12 / 16 px (xs → xl) |
| Focus ring | Color | --palette-focus-700 (light) / --palette-focus-300 (dark), 2px outline 2px offset |
Intents
Intent communicates what an action means. Pick the one that matches the semantic weight, not the color you want. Each intent owns a full triple of default / hover / active tokens in both solid and ghost style — nothing else needs customizing.
Solid & ghost
Every intent is available as solid (filled container with border) or ghost (transparent until hovered). Choose by hierarchy, not by taste.
Solid
Filled buttons command attention. Use them for the action a user is expected to take — one primary on any given view, with secondaries alongside.
Ghost
Ghost buttons sit lighter on the canvas. Use them for tertiary actions, table-row actions, toolbar commands, and anywhere the filled chip would be visual noise.
Sizes
Five sizes, each defined by the nm-button--{size} modifier class. Match the size to the density of the surrounding UI, not to the importance of the action — importance is communicated by intent.
Choosing a size
xs— inline chips, table-cell actions, filter barssm— dense toolbars, compact dialogsmd— default for forms, cards, panel footerslg— marketing hero, onboarding CTAs, empty statesxl— signing surfaces, fullscreen confirmations, touch-first kiosks
Icon variants
A button can appear as label-only, label + leading icon, label + trailing icon, or icon-only. Icons clarify intent — they never replace clear language.
Solid primary · md · four configurations
Leading icon
Use when the icon adds concrete meaning to the label (↓ Download, + Add user, ↻ Refresh). The icon sits to the left of the label.
Trailing icon
Use when the icon indicates direction or state — Continue →, Open menu ▾, External ↗. Don't use trailing icons to decorate an already-clear verb.
Icon-only
Reserve for actions that are universally recognized (✕ close, ⋯ more, ◀ back) or that sit inside a dense bar where a label would break the layout. Icon-only buttons must have an aria-label.
States
Every button responds to four interaction states. Hover and active colors come pre-baked from the tokens — you never hand-pick them.
Primary · md · four states
Focus
Focus is rendered by a 2px --theme-focus outline, 2px offset from the button, that respects :focus-visible. Never suppress the focus ring. In dark theme the focus color shifts to a lighter blue for contrast — handled automatically by the theme layer.
No disabled state
Namirial buttons never ship a disabled appearance. A button that can be clicked but can't act is a dead end — users don't know what's wrong or how to fix it. Instead, keep the button enabled and let it trigger an inline error, field-level validation, or a toast that explains what needs to change.
Light & dark theme
All button tokens are remapped under data-theme="light" and data-theme="dark". Contrast, hover directionality, and focus color are all handled for you — author buttons once, they adapt.
Both previews are locked — they don't follow the page theme switcher. Toggle the page theme to see the rest of the documentation cascade.
Buttons in context
How buttons compose with the rest of the system. These are layout recommendations, not rigid rules — adjust to your surface.
Dialog footer
Primary action right-aligned, ghost secondary to its left. In destructive dialogs swap the primary for negative intent.
Form page footer
Empty state
Toolbar
Do & don't
The subtle rules that keep button hierarchy legible at a glance.
aria-label. Always pair with a tooltip on first hover.Accessibility
Namirial buttons inherit from the native <button> element. The tokens handle contrast; you handle semantics and labeling.
Semantics
- Use
<button type="button">by default. Usetype="submit"only inside a<form>that should submit on Enter. - Never style an
<a>as a button (or vice versa). A button does; a link navigates.
Keyboard
- Tab moves focus; Shift + Tab moves backwards.
- Space and Enter both trigger the button.
- Focus ring uses
:focus-visible, so it appears on keyboard focus but not on mouse click — no override needed.
Contrast
- All seven intents, in both themes, meet WCAG 2.2 AA contrast for label-over-container at every state.
- Focus ring contrast is ≥ 3:1 against both the button and the surrounding background.
Labeling
- Icon-only buttons require
aria-label. Make the label describe the action, not the icon ("Close dialog", not "X icon"). - Toggle buttons (e.g. Bold in a toolbar) require
aria-pressed. - Buttons that open a menu require
aria-haspopupandaria-expanded.
Playground
Configure every axis at once. The code snippet updates as you go — copy it straight into your product.
Token reference
Every button variant resolves to a handful of custom properties. When you need a one-off tweak, override these on a wrapper — never on the .nm-button rule itself.
Per-intent color tokens
| Token | Role |
|---|---|
--nm-button-{intent}-default-bg | Container fill at rest |
--nm-button-{intent}-hover-bg | Fill on hover |
--nm-button-{intent}-active-bg | Fill while pressed |
--nm-button-{intent}-default-border | Border at rest |
--nm-button-{intent}-fg | Label + icon color (solid) |
--nm-button-ghost-{intent}-fg | Label color, ghost style |
{intent} = primary · secondary · accent · positive · negative · warning · info
Per-size geometry values
| Property | Role | xs | sm | md | lg | xl |
|---|---|---|---|---|---|---|
height | Button height | 24px | 32px | 40px | 48px | 56px |
font-size | Label size | 12px | 14px | 16px | 20px | 24px |
padding-inline | Horizontal padding | 8px | 12px | 16px | 24px | 24px |
gap | Icon/label gap | 8px | 8px | 12px | 12px | 16px |
border-radius | Corner radius | 6px | 8px | 10px | 12px | 12px |
Values are baked into .nm-button--{size} modifier classes. No custom properties to override — use a different size class instead.
Implementation
The component uses BEM modifier classes. Import namirial-theme.css and compose classes — no data attributes, no build step.
<link rel="stylesheet" href="namirial-theme.css">
<button class="nm-button nm-button--accent nm-button--md">
Continue
<i class="icon-arrow-right"></i>
</button>CSS classes
| Class | Values | Default |
|---|---|---|
nm-button--{intent} | primary · secondary · accent · positive · negative · warning · info | primary |
nm-button--{style} | ghost (omit for solid) | solid |
nm-button--{size} | xs · sm · md · lg · xl | md |
nm-button--icon-only | square aspect ratio, no horizontal padding | — |