RadCN
Inputsreadycomponentready

Button

A native button and link primitive with RadCN variants, sizing, disabled states, and token-driven styling.

Importimport { Button } from 'radcn/button'
Preview

Live package example

Use the same Button component for actions, secondary choices, and link-style navigation.

Variants

Use the same Button component for actions, secondary choices, and link-style navigation.

Preview
Href Button
import { Button } from 'radcn/button'
import { Spinner } from 'radcn/spinner'

export function ButtonPreview() {
  return (
    <div class="button-preview">
      <Button>Deploy site</Button>
      <Button variant="secondary">Preview</Button>
      <Button variant="outline">View docs</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="destructive">Delete</Button>
      <Button variant="link">Link</Button>
      <Button href="/docs/components/button">Href Button</Button>
      <Button size="sm" variant="outline">
        <svg aria-hidden="true" fill="none" height="16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="16">
          <path d="M7 17 17 7" />
          <path d="M8 7h9v9" />
        </svg>
        New Branch
      </Button>
      <Button disabled size="sm" variant="outline">
        <Spinner ariaLabel="Submitting" />
        Submit
      </Button>
      <Button ariaLabel="Submit" size="icon" variant="outline">
        <svg aria-hidden="true" fill="none" height="16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="16">
          <path d="M7 17 17 7" />
          <path d="M8 7h9v9" />
        </svg>
      </Button>
      <Button ariaLabel="Upload" class="radcn-fixture-rounded-button" size="icon" variant="outline">
        <svg aria-hidden="true" fill="none" height="16" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="16">
          <path d="M7 17 17 7" />
          <path d="M8 7h9v9" />
        </svg>
      </Button>
      <Button size="sm">Small</Button>
      <Button size="lg">Large</Button>
      <Button ariaLabel="Submit small" size="icon-sm" variant="outline">^</Button>
      <Button ariaLabel="Submit large" size="icon-lg" variant="outline">^</Button>
    </div>
  )
}

Installation

Intended future install command. RadCN is private and not published to npm yet, so this snippet documents the target user-facing API rather than something external consumers can run today.

pnpm add radcn # intended future package
import { Button } from 'radcn/button'

Theming

RadCN tokens read the resolved theme from the document. Store the user's preference separately, then resolve system preferences to a concrete light or dark theme before setting package tokens.

<html data-radcn-theme-mode="system" data-radcn-theme="dark">
  ...
</html>

Accessibility

  • Renders a native button by default, preserving keyboard and form behavior without client JavaScript.
  • Renders an anchor when href is provided, so link semantics remain real links.
  • Icon-only buttons can use ariaLabel to provide an accessible name while the icon stays decorative.
  • Supports disabled and aria-disabled states for unavailable actions.

Customization

  • The component is styled through RadCN CSS variables such as --radcn-primary, --radcn-radius, and --radcn-control-height.
  • Variants and sizes are expressed as data attributes and class names so app-level CSS can extend the visual system.
  • Loading buttons are plain composition: render a disabled Button with a nested Spinner.

Remix 3 Notes

  • The Remix 3 port does not wrap React components. It returns host elements from remix/ui and keeps behavior close to the platform.
  • shadcn/ui asChild maps to the explicit href prop in RadCN, avoiding React Slot while preserving link semantics.
  • Composition favors explicit props and package imports instead of a generated component copy inside the consuming app.