Actions

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

PartRoleSource
ContainerFill--nm-button-{intent}-default-bg
ContainerHorizontal paddingpadding-inline — 8 / 12 / 16 / 24 / 24 px (xs → xl)
ContainerHeightheight — 24 / 32 / 40 / 48 / 56 px (xs → xl)
ContainerRadiusborder-radius — 6 / 8 / 10 / 12 / 12 px (xs → xl)
BorderColor--nm-button-{intent}-default-border
BorderWidthborder-width: 1px (fixed)
LabelColor (solid)--nm-button-{intent}-fg
LabelColor (ghost)--nm-button-ghost-{intent}-fg
LabelSizefont-size — 12 / 14 / 16 / 20 / 24 px (xs → xl)
IconsGapgap — 8 / 8 / 12 / 12 / 16 px (xs → xl)
Focus ringColor--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.

Primary

The most important action on the screen. Neutral-dark so it reads as "default" rather than branded. Use exactly one per view.

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Secondary

A supporting action next to the primary — "Cancel", "Back", "Discard". Outlined so it never competes with primary or accent for attention.

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Accent

Namirial teal — reserved for brand moments or calls-to-action that should feel distinctly "Namirial" (onboarding, conversion).

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Positive

Confirms, approves, or completes. Use sparingly — only when the outcome is reversible success (Approve, Publish).

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Negative

Destructive or irreversible actions — delete, revoke, reject. Always pair with a confirmation dialog.

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Warning

Proceed-with-caution actions. The outcome is recoverable but deserves a second look — override, force-publish, dismiss warning.

default
solid
ghost
hover
solid
ghost
active
solid
ghost

Info

Informational, non-committal triggers inside an info panel or help surface — Learn more, View details.

default
solid
ghost
hover
solid
ghost
active
solid
ghost

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.

xs
12px · h 16px · r 6
sm
14px · h 16px · r 8
md
16px · h 24px · r 10
lg
20px · h 24px · r 12
xl
24px · h 32px · r 12

Choosing a size

  • xs — inline chips, table-cell actions, filter bars
  • sm — dense toolbars, compact dialogs
  • md — default for forms, cards, panel footers
  • lg — marketing hero, onboarding CTAs, empty states
  • xl — 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.

Light data-theme="light"
Dark data-theme="dark"

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.

Primary action right-aligned, ghost secondary to its left. In destructive dialogs swap the primary for negative intent.

Empty state

No documents yet
Start your first signing workflow

Toolbar

Do & don't

The subtle rules that keep button hierarchy legible at a glance.

✓Do
Use exactly one primary or accent button per view. Pair it with a secondary or ghost to balance the group.
✕Don't
Don't stack multiple loud intents side by side. Users won't know which action to take — the emphasis cancels itself out.
✓Do
Write the action as a verb phrase. The label should complete the sentence "I want to…"
✕Don't
"Click here", "Submit", and "OK" are vague. Name the outcome so the label is self-explanatory out of context.
✓Do
Use negative intent only for truly destructive actions, and spell out what's being destroyed.
✕Don't
Logging out isn't destructive — use primary or secondary. Save negative intent for irreversible actions.
✓Do
Keep icons single-concept: one leading or one trailing.
✕Don't
Don't stack redundant icons. One icon, chosen for meaning, beats two that repeat each other.
✓Do
Enter a valid email before saving.
Keep the button enabled. When the user clicks, trigger inline validation — they learn the rule by trying.
✕Don't
Don't use a disabled state. A greyed-out button tells users nothing about why they can't proceed.
✓Do
Icon-only buttons require an aria-label. Always pair with a tooltip on first hover.
✕Don't
No aria-label — invisible to screen readers and unclear to sighted users on unfamiliar icons.

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. Use type="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-haspopup and aria-expanded.

Playground

Configure every axis at once. The code snippet updates as you go — copy it straight into your product.

<button class="nm-button nm-button--accent nm-button--md"> <i class="icon-arrow-left"></i>Continue<i class="icon-arrow-right"></i> </button>

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

TokenRole
--nm-button-{intent}-default-bgContainer fill at rest
--nm-button-{intent}-hover-bgFill on hover
--nm-button-{intent}-active-bgFill while pressed
--nm-button-{intent}-default-borderBorder at rest
--nm-button-{intent}-fgLabel + icon color (solid)
--nm-button-ghost-{intent}-fgLabel color, ghost style

{intent} = primary · secondary · accent · positive · negative · warning · info

Per-size geometry values

PropertyRolexssmmdlgxl
heightButton height24px32px40px48px56px
font-sizeLabel size12px14px16px20px24px
padding-inlineHorizontal padding8px12px16px24px24px
gapIcon/label gap8px8px12px12px16px
border-radiusCorner radius6px8px10px12px12px

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

ClassValuesDefault
nm-button--{intent}primary · secondary · accent · positive · negative · warning · infoprimary
nm-button--{style}ghost (omit for solid)solid
nm-button--{size}xs · sm · md · lg · xlmd
nm-button--icon-onlysquare aspect ratio, no horizontal padding—