Skip to main contentSkip to docs navigation

Trigger an action or navigate. Renders as a native button, anchor, or input, or as any custom component via the component prop.

Examples

<Button> renders a native <button type="button"> by default, styled with the color prop for one of Chassis's context colors.

JSX
import { Button } from '@chassis-ui/react'

export const Example = () => {
  return <Button color="primary">Save</Button>
}

Colors

Set color to one of Chassis's context colors to change a button's background and foreground.

JSX
import { Button } from '@chassis-ui/react'
import { COLORS } from '../../utils'

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Button key={color} color={color}>
          {color}
        </Button>
      ))}
    </>
  )
}

Color alone doesn't convey meaning to assistive technology. Pair a context color with visible text describing the action, or add hidden text via the .visually-hidden class when the color itself carries information.

Style variants

Layer variant on top of color to change a button's fill instead of its palette.

Outline

Set variant="outline" for a transparent background with a colored border and text — a lower-emphasis alternative to a solid button in the same color.

JSX
import { Button } from '@chassis-ui/react'
import { COLORS } from '../../utils'

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Button key={color} color={color} variant="outline">
          {color}
        </Button>
      ))}
    </>
  )
}

Some outline colors use a light foreground meant for a dark background — check contrast before using them on a light surface.

Smooth

Set variant="smooth" for a subdued, tinted background in the button's color, softer than the default solid fill.

JSX
import { Button } from '@chassis-ui/react'
import { COLORS } from '../../utils'

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Button key={color} color={color} variant="smooth">
          {color}
        </Button>
      ))}
    </>
  )
}

Set variant="link" to make a button look and behave like a hyperlink while keeping its color and click behavior — a lower-emphasis action inside a toolbar or form. variant="link" is a button-specific style, not a context color: pass it alongside color, not instead of it.

JSX
import { Button } from '@chassis-ui/react'
import { COLORS } from '../../utils'

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Button key={color} color={color} variant="link">
          {color}
        </Button>
      ))}
    </>
  )
}

Root element

Set component to render <Button> as a different element — "a" for navigation, "input" for legacy form markup, or any custom component. href implies component="a" automatically, so setting href alone is enough for a link button.

Link
JSX
import { Button } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Button type="submit" color="primary">
        Button
      </Button>
      <Button component="a" href="#" color="primary" role="button">
        Link
      </Button>
      <Button component="input" type="button" color="primary" value="Input" />
      <Button component="input" type="submit" color="primary" value="Submit" />
      <Button component="input" type="reset" color="primary" value="Reset" />
    </>
  )
}

A button rendered as <a> for something other than navigation — collapsing content, for example — needs an explicit role="button"; Chassis doesn't add it automatically, since not every component="a" usage is a non-navigation action. type only affects <button> and <input>; it has no effect when rendered as <a>.

A plain tag other than "button", "a", or "input" (for example "span") gets keyboard activation, focus handling, and role="button" synthesized automatically, matching native button behavior. A component reference (for example a router's Link) doesn't: it's trusted to bring its own semantics, since stamping role="button" onto the <a> it renders would be wrong.

To render a router's link component with button styling, pass it as the child with asChild, instead of passing it by reference to component. The button's classes, props and ref are merged onto the child element, and the router link still handles navigation:

TSX
import Link from 'next/link'
import { Button } from '@chassis-ui/react/button'

<Button asChild variant="outline">
  <Link href="/login">Log in</Link>
</Button>

A disabled button treats the child as it treats component="a": the link gets aria-disabled="true" and tabindex="-1", and its click is blocked.

This form also works from a React Server Component. component={Link} there fails to build with "Functions cannot be passed directly to Client Components", because a component reference is a function and can't cross the server-to-client boundary. A JSX element can. See Server-side rendering.

Sizes

Set size to "sm" or "lg" to adjust a button's padding and font size; the default renders at md size.

JSX
import { Button } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Button color="primary" size="sm">
        Small
      </Button>
      <Button color="primary">Medium</Button>
      <Button color="primary" size="lg">
        Large
      </Button>
    </>
  )
}

Pressed state

Set pressed to mark a toggle-style button as active — e.g. a formatting toolbar button that stays highlighted while its feature is on. It applies the .active class and sets aria-pressed, so assistive technology announces "button, pressed" instead of treating the button as a navigation link. A button that is a link (href, or an <a> as component or the asChild element) gets the class alone: a link has no pressed state to announce. Give it role="button" if it acts as a toggle, and it takes aria-pressed too.

JSX
import { useState } from 'react'
import { Button } from '@chassis-ui/react'

export const Example = () => {
  const [pressed, setPressed] = useState(false)

  return (
    <Button color="primary" pressed={pressed} onClick={() => setPressed(!pressed)}>
      Bold
    </Button>
  )
}

Disabled state

Set disabled to make a button non-interactive. A native <button> or <input> uses the real disabled attribute, which blocks keyboard and pointer interaction on its own.

JSX
import { Button } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Button color="primary" size="lg" disabled>
      Button
    </Button>
  )
}

<a> has no disabled attribute, so a disabled link button sets aria-disabled="true" and tabindex="-1" instead, and blocks its own click handler and navigation.

JSX
import { Button } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Button component="a" href="#" color="secondary" size="lg" disabled>
      Link
    </Button>
  )
}

Scope

No automatic role="button" on non-navigation links. Rendering <Button> with component="a" for an action rather than navigation (see Root element) still needs an explicit role="button" — Chassis can't distinguish the two cases from href alone.

API

Button

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute specifies the URL of the page the link goes to.
onClick?MouseEventHandler<HTMLAnchorElement | HTMLButtonElement | HTMLInputElement>—
Fires on click. Typed for every element component can actually render (button, a, input, or a custom component), rather than narrowed to HTMLButtonElement alone.
pressed?boolean—
Marks the button as pressed for toggle-style usage (e.g. a formatting toolbar button). Applies the .active class and sets aria-pressed so assistive technology announces "button, pressed" rather than treating the button as a navigation link. A link (href, or an <a> as component or the asChild element) has no pressed state to announce: it gets the class alone, unless you give it role="button".
ref?any—
shape?Shapes—
Select the shape of the component.
size?"sm" | "lg"—
Size the component sm or lg.
type?"button" | "submit" | "reset"—
Specifies the type of button. Always specify the type attribute for the <button> element. Different browsers may use different default types for the <button> element.
variant?"link" | "basic" | "outline" | "smooth"—
Set the button style variant. Same as ContextStyle, but solid (the unmodified default look) doesn't apply as a class, and link — button-specific, not a context color — makes the button look and behave like a hyperlink while keeping its color.