shadcn-remix
GitHub

Button

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

import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonDemo() {
import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonDemo() {
  return () => (
    <div
      mix={css({
        display: 'flex',
        flexWrap: 'wrap',
        alignItems: 'center',
        gap: '0.5rem',
        '@media (min-width: 768px)': { flexDirection: 'row' },
      })}
    >
      <Button variant="outline">Button</Button>
      <Button variant="outline" size="icon" aria-label="Submit">
        <ArrowUpIcon />
      </Button>
    </div>
  )
}

Installation

$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/button.json

Usage

import { Button } from '#app/ui/button.tsx'
<Button variant="outline">Button</Button>

Examples

Size

Use the size prop to change the size of the button.

import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpRightIcon } from '#app/ui/icons.tsx'

const row = css({ display: 'flex', alignItems: 'flex-start', gap: '0.5rem' })
import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpRightIcon } from '#app/ui/icons.tsx'

const row = css({ display: 'flex', alignItems: 'flex-start', gap: '0.5rem' })

export function ButtonSize() {
  return () => (
    <div
      mix={css({
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'flex-start',
        gap: '2rem',
        '@media (min-width: 640px)': { flexDirection: 'row' },
      })}
    >
      <div mix={row}>
        <Button size="sm" variant="outline">
          Small
        </Button>
        <Button size="icon-sm" aria-label="Submit" variant="outline">
          <ArrowUpRightIcon />
        </Button>
      </div>
      <div mix={row}>
        <Button variant="outline">Default</Button>
        <Button size="icon" aria-label="Submit" variant="outline">
          <ArrowUpRightIcon />
        </Button>
      </div>
      <div mix={row}>
        <Button variant="outline" size="lg">
          Large
        </Button>
        <Button size="icon-lg" aria-label="Submit" variant="outline">
          <ArrowUpRightIcon />
        </Button>
      </div>
    </div>
  )
}

Default

import { Button } from '#app/ui/button.tsx'

export function ButtonDefault() {
  return () => <Button>Button</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonDefault() {
  return () => <Button>Button</Button>
}

Outline

import { Button } from '#app/ui/button.tsx'

export function ButtonOutline() {
  return () => <Button variant="outline">Outline</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonOutline() {
  return () => <Button variant="outline">Outline</Button>
}

Secondary

import { Button } from '#app/ui/button.tsx'

export function ButtonSecondary() {
  return () => <Button variant="secondary">Secondary</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonSecondary() {
  return () => <Button variant="secondary">Secondary</Button>
}

Ghost

import { Button } from '#app/ui/button.tsx'

export function ButtonGhost() {
  return () => <Button variant="ghost">Ghost</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonGhost() {
  return () => <Button variant="ghost">Ghost</Button>
}

Destructive

import { Button } from '#app/ui/button.tsx'

export function ButtonDestructive() {
  return () => <Button variant="destructive">Destructive</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonDestructive() {
  return () => <Button variant="destructive">Destructive</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonLink() {
  return () => <Button variant="link">Link</Button>
}
import { Button } from '#app/ui/button.tsx'

export function ButtonLink() {
  return () => <Button variant="link">Link</Button>
}

Icon

import { Button } from '#app/ui/button.tsx'
import { CircleFadingArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonIcon() {
  return () => (
    <Button variant="outline" size="icon" aria-label="Upgrade">
import { Button } from '#app/ui/button.tsx'
import { CircleFadingArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonIcon() {
  return () => (
    <Button variant="outline" size="icon" aria-label="Upgrade">
      <CircleFadingArrowUpIcon />
    </Button>
  )
}

With Icon

import { Button } from '#app/ui/button.tsx'
import { GitBranchIcon } from '#app/ui/icons.tsx'

export function ButtonWithIcon() {
  return () => (
    <Button variant="outline" size="sm">
import { Button } from '#app/ui/button.tsx'
import { GitBranchIcon } from '#app/ui/icons.tsx'

export function ButtonWithIcon() {
  return () => (
    <Button variant="outline" size="sm">
      <GitBranchIcon /> New Branch
    </Button>
  )
}

Rounded

Pass a css(...) mix to override styles, the equivalent of className="rounded-full".

import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonRounded() {
import { css } from 'remix/component'

import { Button } from '#app/ui/button.tsx'
import { ArrowUpIcon } from '#app/ui/icons.tsx'

export function ButtonRounded() {
  return () => (
    <div mix={css({ display: 'flex', flexDirection: 'column', gap: '2rem' })}>
      <Button
        variant="outline"
        size="icon"
        aria-label="Scroll to top"
        mix={css({ borderRadius: '9999px' })}
      >
        <ArrowUpIcon />
      </Button>
    </div>
  )
}

Spinner

Render a <Spinner /> inside the button to show a loading state.

import { Button } from '#app/ui/button.tsx'
import { Spinner } from '#app/ui/spinner.tsx'

export function ButtonLoading() {
  return () => (
    <Button size="sm" variant="outline" disabled>
import { Button } from '#app/ui/button.tsx'
import { Spinner } from '#app/ui/spinner.tsx'

export function ButtonLoading() {
  return () => (
    <Button size="sm" variant="outline" disabled>
      <Spinner />
      Submit
    </Button>
  )
}

As Child

Remix components have no asChild. Apply buttonVariants() to any element to make it look like a button, here a link.

import { buttonVariants } from '#app/ui/button.tsx'

export function ButtonAsChild() {
  return () => (
    <a href="#login" mix={buttonVariants()}>
      Login
import { buttonVariants } from '#app/ui/button.tsx'

export function ButtonAsChild() {
  return () => (
    <a href="#login" mix={buttonVariants()}>
      Login
    </a>
  )
}

API Reference

Button

Renders a native <button>. Accepts every <button> attribute plus mix.

PropTypeDefault
variant"default" | "destructive" | "outline" | "secondary" | "ghost" | "link""default"
size"default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg""default"
mixMixValue-

buttonVariants

Returns the button styles as a mix for any element.

PropTypeDefault
variantButtonVariant"default"
sizeButtonSize"default"