Skip to content
Ndop UI

Button

Displays a button or a component that looks like a button.

import { Component } from '@angular/core';
import { Button } from '@/ui/button/button';

/** Every Button variant, side by side. */
@Component({
  selector: 'example-button-variants',
  imports: [Button],
  template: `
    <div class="flex flex-wrap items-center gap-2">
      <button ndButton>Default</button>
      <button ndButton variant="secondary">Secondary</button>
      <button ndButton variant="outline">Outline</button>
      <button ndButton variant="ghost">Ghost</button>
      <button ndButton variant="destructive">Destructive</button>
      <button ndButton variant="link">Link</button>
    </div>
  `,
})
export class ButtonVariantsExample {}

Buttons start actions: submitting a form, opening a dialog, saving a change. ndButton styles a native button, or an a when the action navigates, so both keep their native keyboard behavior and semantics. Six variants set the emphasis, from default for the main action to link for an action that reads like text, and eight sizes cover text and icon-only buttons.

Installation

npx @ndop/cli add button

Usage

import { Button } from '@/ui/button/button';
<div class="flex flex-wrap items-center gap-2">
  <button ndButton>Default</button>
  <button ndButton variant="secondary">Secondary</button>
  <button ndButton variant="outline">Outline</button>
  <button ndButton variant="ghost">Ghost</button>
  <button ndButton variant="destructive">Destructive</button>
  <button ndButton variant="link">Link</button>
</div>

Examples

Button anchor

Button styles on links, where shadcn uses asChild: an enabled link, and a disabled one that stays focusable and announces itself as disabled.

import { Component, signal } from '@angular/core';
import { Button } from '@/ui/button/button';

/**
 * Button styles on links, where shadcn uses `asChild`: an enabled link, and
 * a disabled one that stays focusable and announces itself as disabled.
 */
@Component({
  selector: 'example-button-anchor',
  imports: [Button],
  template: `
    <div class="flex flex-wrap items-center gap-2">
      <a ndButton href="#login">Login</a>
      <a ndButton variant="outline" href="#billing" [disabled]="locked()">
        Billing
      </a>
    </div>
  `,
})
export class ButtonAnchorExample {
  protected readonly locked = signal(true);
}

The link variant: a button that looks like a text link.

import { Component } from '@angular/core';
import { Button } from '@/ui/button/button';

/** The `link` variant: a button that looks like a text link. */
@Component({
  selector: 'example-button-link',
  imports: [Button],
  template: `<button ndButton variant="link">Link</button>`,
})
export class ButtonLinkExample {}

Button sizes

Button sizes, including an icon-only button with an accessible name.

import { Component } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { Button } from '@/ui/button/button';

/** Button sizes, including an icon-only button with an accessible name. */
@Component({
  selector: 'example-button-sizes',
  imports: [Button, NdIcon],
  template: `
    <div class="flex flex-wrap items-center gap-2">
      <button ndButton variant="outline" size="xs">Extra small</button>
      <button ndButton variant="outline" size="sm">Small</button>
      <button ndButton variant="outline">Default</button>
      <button ndButton variant="outline" size="lg">Large</button>
      <button ndButton variant="outline" size="icon" aria-label="Dismiss">
        <svg ndIcon="x"></svg>
      </button>
    </div>
  `,
})
export class ButtonSizesExample {}

Accessibility

Implements the Button pattern of the WAI-ARIA Authoring Practices.

Keyboard

Keys the component handles.

Key Action
EnterActivates the button, or follows the link; does nothing while disabled.
SpaceActivates a button; does nothing while disabled. Links don't react to Space.

Focus

  • A disabled button and a disabled a are removed from the tab order.
  • Activation does not move focus.

Right-to-left

Nothing mirrors.

API reference

Button

button[ndButton], a[ndButton]role native (button / link)

Styled button for a native button or an a, with the @ndop/primitives/button behavior (safe default type, disabled links).

Manages aria-disabled.

Button binding Type Default
[variant]
Visual style.
'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link''default'
[size]
Height, padding and icon size.
'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg''default'
[class]
Extra classes, merged last so they win.
string''
[disabled]
Whether the button or link is disabled.
booleanfalse
Data attribute Values
data-slotbutton
data-variant —
data-size —
data-disabled —

Agent notes

Do

  • Use one default button for the main action of a view, and outline, secondary or ghost for the others.
  • Put ndButton on an a with an href when the action navigates, so it opens in a new tab and shows its URL like any link.
  • Give icon-only buttons (size="icon") an aria-label.
  • Use destructive for actions that delete or can't be undone, and confirm them in a dialog.

Don't

  • Don't put ndButton on a div or span; it only applies to button and a, which keyboard and screen reader users can operate.
  • Don't disable a submit button to signal invalid input; keep it enabled and show the errors when it is pressed.
  • Don't use link for a primary action; it is meant to read like text.