---
title: Button
description: Interactive button component with multiple variants and sizes.
icon: computer-mouse-button-left

---

import { ComponentPreview } from '/snippets/component-preview.mdx'

Buttons trigger actions and communicate intent. The `variant` parameter signals what kind of action the button performs, while `size` controls its dimensions.

## Basic Usage

<ComponentPreview json={{"view":{"type":"Button","label":"Save Changes","variant":"default","size":"default","disabled":false}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQnV0dG9uCgpCdXR0b24oIlNhdmUgQ2hhbmdlcyIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Button

Button("Save Changes")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "type": "Button",
    "label": "Save Changes",
    "variant": "default",
    "size": "default",
    "disabled": false
  }
}
```
</CodeGroup>
</ComponentPreview>

The label can be passed as a positional argument or as a keyword (`label="Save Changes"`).

## Variants

Each variant communicates a different intent to the user:

<ComponentPreview json={{"view":{"cssClass":"gap-8 grid-cols-3","type":"Grid","children":[{"type":"Button","label":"Default","variant":"default","size":"default","disabled":false},{"type":"Button","label":"Destructive","variant":"destructive","size":"default","disabled":false},{"type":"Button","label":"Outline","variant":"outline","size":"default","disabled":false},{"type":"Button","label":"Secondary","variant":"secondary","size":"default","disabled":false},{"type":"Button","label":"Ghost","variant":"ghost","size":"default","disabled":false},{"type":"Button","label":"Link","variant":"link","size":"default","disabled":false},{"type":"Button","label":"Success","variant":"success","size":"default","disabled":false},{"type":"Button","label":"Warning","variant":"warning","size":"default","disabled":false},{"type":"Button","label":"Info","variant":"info","size":"default","disabled":false}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Button,
    Grid,
)

with Grid(columns=3, gap=8):
    Button("Default", variant="default")
    Button("Destructive", variant="destructive")
    Button("Outline", variant="outline")
    Button("Secondary", variant="secondary")
    Button("Ghost", variant="ghost")
    Button("Link", variant="link")
    Button("Success", variant="success")
    Button("Warning", variant="warning")
    Button("Info", variant="info")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-8 grid-cols-3",
    "type": "Grid",
    "children": [
      {
        "type": "Button",
        "label": "Default",
        "variant": "default",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Destructive",
        "variant": "destructive",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Outline",
        "variant": "outline",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Secondary",
        "variant": "secondary",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Ghost",
        "variant": "ghost",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Link",
        "variant": "link",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Success",
        "variant": "success",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Warning",
        "variant": "warning",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Info",
        "variant": "info",
        "size": "default",
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Sizes

<ComponentPreview json={{"view":{"cssClass":"gap-3 items-center","type":"Row","children":[{"type":"Button","label":"Tiny","variant":"default","size":"xs","disabled":false},{"type":"Button","label":"Small","variant":"default","size":"sm","disabled":false},{"type":"Button","label":"Default","variant":"default","size":"default","disabled":false},{"type":"Button","label":"Large","variant":"default","size":"lg","disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQnV0dG9uLAogICAgUm93LAopCgp3aXRoIFJvdyhnYXA9MywgY3NzX2NsYXNzPSJpdGVtcy1jZW50ZXIiKToKICAgIEJ1dHRvbigiVGlueSIsIHNpemU9InhzIikKICAgIEJ1dHRvbigiU21hbGwiLCBzaXplPSJzbSIpCiAgICBCdXR0b24oIkRlZmF1bHQiLCBzaXplPSJkZWZhdWx0IikKICAgIEJ1dHRvbigiTGFyZ2UiLCBzaXplPSJsZyIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Button,
    Row,
)

with Row(gap=3, css_class="items-center"):
    Button("Tiny", size="xs")
    Button("Small", size="sm")
    Button("Default", size="default")
    Button("Large", size="lg")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3 items-center",
    "type": "Row",
    "children": [
      {
        "type": "Button",
        "label": "Tiny",
        "variant": "default",
        "size": "xs",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Small",
        "variant": "default",
        "size": "sm",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Default",
        "variant": "default",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Large",
        "variant": "default",
        "size": "lg",
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## With Icons

Buttons accept an `icon` prop (any [lucide icon name](https://lucide.dev/icons) in kebab-case). The icon renders before the label text.

<ComponentPreview json={{"view":{"cssClass":"gap-3 items-center","type":"Row","children":[{"type":"Button","label":"Download","icon":"download","variant":"default","size":"default","disabled":false},{"type":"Button","label":"Settings","icon":"settings","variant":"outline","size":"default","disabled":false},{"type":"Button","label":"Delete","icon":"trash-2","variant":"destructive","size":"default","disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQnV0dG9uLCBSb3cKCndpdGggUm93KGdhcD0zLCBjc3NfY2xhc3M9Iml0ZW1zLWNlbnRlciIpOgogICAgQnV0dG9uKCJEb3dubG9hZCIsIGljb249ImRvd25sb2FkIikKICAgIEJ1dHRvbigiU2V0dGluZ3MiLCBpY29uPSJzZXR0aW5ncyIsIHZhcmlhbnQ9Im91dGxpbmUiKQogICAgQnV0dG9uKCJEZWxldGUiLCBpY29uPSJ0cmFzaC0yIiwgdmFyaWFudD0iZGVzdHJ1Y3RpdmUiKQo=">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Button, Row

with Row(gap=3, css_class="items-center"):
    Button("Download", icon="download")
    Button("Settings", icon="settings", variant="outline")
    Button("Delete", icon="trash-2", variant="destructive")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3 items-center",
    "type": "Row",
    "children": [
      {
        "type": "Button",
        "label": "Download",
        "icon": "download",
        "variant": "default",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Settings",
        "icon": "settings",
        "variant": "outline",
        "size": "default",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "Delete",
        "icon": "trash-2",
        "variant": "destructive",
        "size": "default",
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Icon Sizes

Square buttons optimized for single icons. Use `icon` with an icon-size variant for icon-only buttons.

<ComponentPreview json={{"view":{"cssClass":"gap-3 items-center","type":"Row","children":[{"type":"Button","label":"","icon":"plus","variant":"default","size":"icon-xs","disabled":false},{"type":"Button","label":"","icon":"plus","variant":"default","size":"icon-sm","disabled":false},{"type":"Button","label":"","icon":"plus","variant":"default","size":"icon","disabled":false},{"type":"Button","label":"","icon":"plus","variant":"default","size":"icon-lg","disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQnV0dG9uLCBSb3cKCndpdGggUm93KGdhcD0zLCBjc3NfY2xhc3M9Iml0ZW1zLWNlbnRlciIpOgogICAgQnV0dG9uKCIiLCBpY29uPSJwbHVzIiwgc2l6ZT0iaWNvbi14cyIpCiAgICBCdXR0b24oIiIsIGljb249InBsdXMiLCBzaXplPSJpY29uLXNtIikKICAgIEJ1dHRvbigiIiwgaWNvbj0icGx1cyIsIHNpemU9Imljb24iKQogICAgQnV0dG9uKCIiLCBpY29uPSJwbHVzIiwgc2l6ZT0iaWNvbi1sZyIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Button, Row

with Row(gap=3, css_class="items-center"):
    Button("", icon="plus", size="icon-xs")
    Button("", icon="plus", size="icon-sm")
    Button("", icon="plus", size="icon")
    Button("", icon="plus", size="icon-lg")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3 items-center",
    "type": "Row",
    "children": [
      {
        "type": "Button",
        "label": "",
        "icon": "plus",
        "variant": "default",
        "size": "icon-xs",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "",
        "icon": "plus",
        "variant": "default",
        "size": "icon-sm",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "",
        "icon": "plus",
        "variant": "default",
        "size": "icon",
        "disabled": false
      },
      {
        "type": "Button",
        "label": "",
        "icon": "plus",
        "variant": "default",
        "size": "icon-lg",
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Disabled State

<ComponentPreview json={{"view":{"type":"Button","label":"Unavailable","variant":"default","size":"default","disabled":true}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQnV0dG9uCgpCdXR0b24oIlVuYXZhaWxhYmxlIiwgZGlzYWJsZWQ9VHJ1ZSkK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Button

Button("Unavailable", disabled=True)
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "type": "Button",
    "label": "Unavailable",
    "variant": "default",
    "size": "default",
    "disabled": true
  }
}
```
</CodeGroup>
</ComponentPreview>

## Custom Styling

Every component accepts `css_class` for additional Tailwind CSS classes. When your classes target the same CSS property as a built-in style (like `rounded-full` vs the default `rounded-md`), the built-in class is automatically removed so your override wins cleanly:

<ComponentPreview json={{"view":{"cssClass":"gap-3 items-start w-full","type":"Column","children":[{"cssClass":"w-full bg-emerald-500","type":"Button","label":"Full Width Emerald","variant":"default","size":"default","disabled":false},{"cssClass":"rounded-full bg-rose-500","type":"Button","label":"Pill Shape Rose","variant":"default","size":"default","disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQnV0dG9uLAogICAgQ29sdW1uLAopCgp3aXRoIENvbHVtbihnYXA9MywgY3NzX2NsYXNzPSJpdGVtcy1zdGFydCB3LWZ1bGwiKToKICAgIEJ1dHRvbigiRnVsbCBXaWR0aCBFbWVyYWxkIiwgY3NzX2NsYXNzPSJ3LWZ1bGwgYmctZW1lcmFsZC01MDAiKQogICAgQnV0dG9uKCJQaWxsIFNoYXBlIFJvc2UiLCBjc3NfY2xhc3M9InJvdW5kZWQtZnVsbCBiZy1yb3NlLTUwMCIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Button,
    Column,
)

with Column(gap=3, css_class="items-start w-full"):
    Button("Full Width Emerald", css_class="w-full bg-emerald-500")
    Button("Pill Shape Rose", css_class="rounded-full bg-rose-500")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3 items-start w-full",
    "type": "Column",
    "children": [
      {
        "cssClass": "w-full bg-emerald-500",
        "type": "Button",
        "label": "Full Width Emerald",
        "variant": "default",
        "size": "default",
        "disabled": false
      },
      {
        "cssClass": "rounded-full bg-rose-500",
        "type": "Button",
        "label": "Pill Shape Rose",
        "variant": "default",
        "size": "default",
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## API Reference

<Card icon="code" title="Button Parameters">
<ParamField body="label" type="str" required>
  Button text. Can be passed as a positional argument.
</ParamField>

<ParamField body="icon" type="str | None" default="None">
  Lucide icon name in kebab-case (e.g., `"arrow-right"`, `"trash-2"`). Browse icons at [lucide.dev/icons](https://lucide.dev/icons).
</ParamField>

<ParamField body="variant" type="str" default="default">
  Visual style: `"default"`, `"destructive"`, `"outline"`, `"secondary"`, `"ghost"`, `"link"`, `"success"`, `"warning"`, `"info"`.
</ParamField>

<ParamField body="size" type="str" default="default">
  Button dimensions: `"default"`, `"xs"`, `"sm"`, `"lg"`, `"icon"`, `"icon-xs"`, `"icon-sm"`, `"icon-lg"`.
</ParamField>

<ParamField body="disabled" type="bool | str" default="False">
  Whether the button is non-interactive. Accepts a template expression like `"{{ not $item.name }}"` for conditional disabling.
</ParamField>

<ParamField body="css_class" type="str | None" default="None">
  Additional Tailwind CSS classes appended to the component's built-in styles.
</ParamField>
</Card>

## Protocol Reference

```json Button
{
  "type": "Button",
  "label": "string (required)",
  "icon?": "string",
  "variant?": "default | destructive | outline | secondary | ghost | link | success | warning | info",
  "size?": "default | xs | sm | lg | icon | icon-xs | icon-sm | icon-lg",
  "disabled?": "boolean | string",
  "onClick?": "Action | Action[]",
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Button](/protocol/button).
