Skip to content

Button

Native-first button styles with variants and sizes; no runtime and no custom element.

Primitive · form

Terminal window
npx shadcn@latest add https://ndigo.dev/r/button.json

To use the shorter @ndigo/button form, configure the namespace in components.json.

Source Target Type
registry/ui/button/nd-button.css @ui/nd-button/nd-button.css registry:file

See this component rendered live on the live examples page.

None.

nd-button.css styles the native <button> (and, for navigation, <a href>) with variants and sizes. There is no custom element and no JavaScript: form participation, disabled semantics, keyboard activation, and accessible names all come from the platform.

<button class="nd-button" data-variant="primary">Save</button>
<button class="nd-button">Cancel</button>
<button class="nd-button" data-variant="ghost" data-size="sm">Skip</button>
<button class="nd-button" data-variant="danger">Delete</button>

Use <button type="submit"> inside a form for submission. Use <a class="nd-button" href="..."> only for navigation; a link is not a button.

data-variant Use
primary The main action in a view
secondary Default; neutral actions (also the no-attribute case)
ghost Low-emphasis actions in dense surfaces
danger Destructive actions, rendered as an outline
data-size Height Use
sm 2rem Dense toolbars and table rows
md 2.5rem Default; no attribute needed
lg 3rem Page-level calls to action
  • disabled on <button> — native disabled semantics.
  • aria-disabled="true" — for link-styled buttons that must stay focusable; pair it with removing href and suppressing the click handler.
  • :focus-visible uses the shared --nd-focus-ring-* tokens.

Keep the accessible name in the button’s text. Icon-only buttons must carry an aria-label. The styles never replace the native element, so screen-reader and keyboard behaviour is unchanged. The danger variant is an outline rather than a solid fill so the label keeps its contrast in both themes.

Import nd-button.css once in the application stylesheet, after the design tokens:

@import './nd-button.css';

Every value comes from a --nd-* token. Override the tokens or the --nd-button-* locals; do not fork the selectors.