Caprice LogoCaprice UI

Button

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

Installation

npx shadcn@latest add @caprice/button

Usage

import { Button } from "@/components/caprice-ui/button"
<Button variant="outline">Button</Button>

Examples

Rendering as another tag

You can use the render prop to make another component look like a button. Here's an example of a link that looks like a button.

import { Button } from '@caprice-ui/react/button';import Link from 'next/link';export default function ButtonRenderLink() {  return (    <Button nativeButton={false} render={<Link href="/login" />}>      Login    </Button>  );}

The button can remain keyboard accessible while being rendered as another tag, such as a <div>, by specifying nativeButton={false}.

import { Button } from '@/components/caprice-ui/button';

<Button render={<div />} nativeButton={false}>
  Button that can contain complex children
</Button>

Focusable When Disabled

For buttons that enter a loading state after being clicked, specify the focusableWhenDisabled prop to ensure focus remains on the button when it becomes disabled. This prevents focus from being lost and maintains the tab order.

Sizes

Variant

Primary (default)

Outline

Secondary

Ghost

Destructive

Icon

With Icon

The spacing between the icon and the text is automatically adjusted based on the size of the button. You do not need any margin on the icon.

Rounded

Use the rounded-full class to make the button rounded.

Spinner

Full Width

Differences with shadcn/ui / Radix

If you're familiar with Radix UI and shadcn/ui, most patterns will carry over. This guide points out the differences so you can start using Caprice UI without surprises.

Key changes

Featureshadcn/uiCaprice UI
PrimitiveRadix Slot + native <button>Base UI Button
CompositionasChild proprender prop (see example)
Sizesdefault, sm, lg, icon, icon-sm, icon-lgsm, md, lg, xl, 2xl, icon, icon-sm, icon-lg, icon-xl, icon-2xl
Default variantdefaultprimary
Default sizedefaultmd
Press eventsStandard onClick onlyonPress, onPressStart, onPressChange, onPressEnd, onPressUp
Pressed stateNoneScale + inset shadow
Disabled attribute:disableddata-disabled
Focusable when disabledNoPossible (see example)
Focus indicatorRing (ring-[3px])Outline (outline-2)

The xl and 2xl sizes (48px & 56px) are designed with accessibility in mind. They exceed WCAG 2.1's 44×44px minimum touch target, match Material Design's 48dp guideline, and reduce missed taps for users with motor impairments or limited dexterity.

Use them for primary CTAs, mobile interfaces, or anywhere a larger hit area improves the experience.

Alternatively, you can check the touch-hitbox utility for a more flexible approach.

Comparison Example

shadcn/ui
<Button variant="default" size="default" asChild>
  <Link href="/login">Login</Link>
</Button>
Caprice UI
<Button variant="primary" size="md" render={<Link href="/login" />} nativeButton={false}>
  Login
</Button>

Accessibility

  • Icon-only buttons require an aria-label to provide an accessible name. Consider wrapping with a Tooltip for additional context.
  • Loading states: When the button enters a loading state, use the focusableWhenDisabled prop to maintain focus and prevent the user from losing their place in the tab order. This automatically applies aria-disabled="true" to communicate the unavailable state to assistive technologies.
  • Keyboard interaction: The <button> element responds to both Space and Enter keys. When rendered as <a>, only Enter triggers the action.
  • Disabled buttons: The component uses data-disabled for styling and can optionally remain focusable via focusableWhenDisabled, allowing screen reader users to discover why a button is unavailable.

API Reference

Prop

Type