> ## Documentation Index
> Fetch the complete documentation index at: https://prefab.prefect.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Button

> Interactive button component with multiple variants and sizes.

export const ComponentPreview = ({json, height, resizable, bare, hideJson, playground, children}) => {
  const hostRef = React.useRef(null);
  const handleRef = React.useRef(null);
  const cardRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const [previewWidth, setPreviewWidth] = React.useState(null);
  const [isDragging, setIsDragging] = React.useState(false);
  const [playgroundHref, setPlaygroundHref] = React.useState(null);
  React.useEffect(function () {
    if (!playground) return;
    var isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
    var path = isLocal ? "/playground" : "/docs/playground";
    var url = new URL(path, window.location.href);
    url.hash = "code=" + playground;
    setPlaygroundHref(url.href);
  }, [playground]);
  var jsonStr = typeof json === "string" ? json : JSON.stringify(json, null, 2);
  React.useEffect(function () {
    if (cardRef.current) {
      var card = cardRef.current.closest(".group");
      if (card) card.classList.remove("group");
    }
    var host = hostRef.current;
    if (!host || !json) return;
    function mount() {
      if (!window.__prefab || !host) return;
      var dark = document.documentElement.classList.contains("dark");
      handleRef.current = window.__prefab.mountPreview(host, jsonStr, {
        dark: dark
      });
      if (bare && host.shadowRoot) {
        var m = host.shadowRoot.querySelector("[data-prefab-mount]");
        if (m) m.style.background = "transparent";
      }
    }
    if (window.__prefab) {
      mount();
    } else {
      if (!window.__prefabLoading) {
        if (!window.__prefabReady) {
          var s = document.createElement("script");
          s.src = "/renderer.js";
          document.head.appendChild(s);
        }
        window.__prefabLoading = new Promise(function (resolve) {
          function check() {
            if (window.__prefabReady) {
              window.__prefabReady.then(resolve);
            } else {
              setTimeout(check, 10);
            }
          }
          check();
        });
      }
      window.__prefabLoading.then(mount);
    }
    var observer = new MutationObserver(function () {
      var dark = document.documentElement.classList.contains("dark");
      if (handleRef.current) handleRef.current.setDark(dark);
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return function () {
      observer.disconnect();
      if (handleRef.current) {
        handleRef.current.unmount();
        handleRef.current = null;
      }
    };
  }, [json]);
  function startResize(e) {
    e.preventDefault();
    var startX = e.clientX;
    var startW = hostRef.current ? hostRef.current.offsetWidth : 0;
    var maxW = containerRef.current ? containerRef.current.offsetWidth - 10 : startW;
    setIsDragging(true);
    function onMove(ev) {
      var w = Math.max(260, Math.min(startW + (ev.clientX - startX), maxW));
      setPreviewWidth(w);
    }
    function onUp() {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      setIsDragging(false);
    }
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  }
  if (bare) {
    return <div ref={hostRef} />;
  }
  if (resizable) {
    return <Card>
        <div ref={cardRef} />
        <div ref={containerRef} style={{
      display: "flex",
      position: "relative",
      overflow: "hidden"
    }}>
          <div ref={hostRef} style={{
      flex: previewWidth ? "none" : 1,
      width: previewWidth ? previewWidth + "px" : undefined,
      minWidth: 0
    }} />
          <div onMouseDown={startResize} style={{
      width: "14px",
      flexShrink: 0,
      cursor: "col-resize",
      background: isDragging ? "var(--border, #e5e7eb)" : "color-mix(in srgb, var(--border, #e5e7eb) 40%, transparent)",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      transition: "background 0.15s",
      userSelect: "none"
    }}>
            <svg width="6" height="24" style={{
      opacity: 0.5
    }}>
              <circle cx="2" cy="4" r="1.2" fill="currentColor" />
              <circle cx="2" cy="9" r="1.2" fill="currentColor" />
              <circle cx="2" cy="14" r="1.2" fill="currentColor" />
              <circle cx="2" cy="19" r="1.2" fill="currentColor" />
              <circle cx="5" cy="4" r="1.2" fill="currentColor" />
              <circle cx="5" cy="9" r="1.2" fill="currentColor" />
              <circle cx="5" cy="14" r="1.2" fill="currentColor" />
              <circle cx="5" cy="19" r="1.2" fill="currentColor" />
            </svg>
          </div>
          <div style={{
      flex: previewWidth ? 1 : "0 0 24px",
      minWidth: "24px",
      background: "repeating-linear-gradient(-45deg, transparent, transparent 3px, var(--border, #e5e7eb) 3px, var(--border, #e5e7eb) 4px)",
      opacity: 0.4
    }} />
          {previewWidth && <div style={{
      position: "absolute",
      bottom: "8px",
      right: "8px",
      background: "var(--background, white)",
      border: "1px solid var(--border, #e5e7eb)",
      borderRadius: "4px",
      padding: "1px 6px",
      fontSize: "11px",
      fontFamily: "monospace",
      color: "var(--muted-foreground, #6b7280)",
      pointerEvents: "none"
    }}>
              {previewWidth}px
            </div>}
        </div>
        {playgroundHref && <div style={{
      display: "flex",
      justifyContent: "flex-end",
      padding: "4px 0 8px"
    }}>
            <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
      fontSize: "11px",
      opacity: 0.4,
      textDecoration: "none",
      textDecorationLine: "none",
      borderBottom: "none",
      boxShadow: "none",
      display: "inline-flex",
      alignItems: "center",
      gap: "3px",
      transition: "opacity 0.15s",
      fontWeight: 400
    }} onMouseOver={function (e) {
      e.currentTarget.style.opacity = "0.6";
    }} onMouseOut={function (e) {
      e.currentTarget.style.opacity = "0.4";
    }}>
              Edit in Playground
              <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
            </a>
          </div>}
        <div style={{
      marginBottom: "-2rem"
    }}>{children}</div>
      </Card>;
  }
  return <Card>
      <div ref={cardRef} />
      <div ref={hostRef} />
      {playgroundHref && <div style={{
    display: "flex",
    justifyContent: "flex-end",
    padding: "4px 0 8px"
  }}>
          <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
    fontSize: "11px",
    opacity: 0.4,
    textDecoration: "none",
    textDecorationLine: "none",
    borderBottom: "none",
    boxShadow: "none",
    display: "inline-flex",
    alignItems: "center",
    gap: "3px",
    transition: "opacity 0.15s",
    fontWeight: 400
  }} onMouseOver={function (e) {
    e.currentTarget.style.opacity = "0.6";
  }} onMouseOut={function (e) {
    e.currentTarget.style.opacity = "0.4";
  }}>
            Edit in Playground
            <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
          </a>
        </div>}
      <div style={{
    marginBottom: "-2rem"
  }}>{children}</div>
    </Card>;
};

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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Button

    Button("Save Changes")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQnV0dG9uLAogICAgR3JpZCwKKQoKd2l0aCBHcmlkKGNvbHVtbnM9MywgZ2FwPTgpOgogICAgQnV0dG9uKCJEZWZhdWx0IiwgdmFyaWFudD0iZGVmYXVsdCIpCiAgICBCdXR0b24oIkRlc3RydWN0aXZlIiwgdmFyaWFudD0iZGVzdHJ1Y3RpdmUiKQogICAgQnV0dG9uKCJPdXRsaW5lIiwgdmFyaWFudD0ib3V0bGluZSIpCiAgICBCdXR0b24oIlNlY29uZGFyeSIsIHZhcmlhbnQ9InNlY29uZGFyeSIpCiAgICBCdXR0b24oIkdob3N0IiwgdmFyaWFudD0iZ2hvc3QiKQogICAgQnV0dG9uKCJMaW5rIiwgdmFyaWFudD0ibGluayIpCiAgICBCdXR0b24oIlN1Y2Nlc3MiLCB2YXJpYW50PSJzdWNjZXNzIikKICAgIEJ1dHRvbigiV2FybmluZyIsIHZhcmlhbnQ9Indhcm5pbmciKQogICAgQnV0dG9uKCJJbmZvIiwgdmFyaWFudD0iaW5mbyIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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

The `size` prop scales a button's padding and text from `xs` through `lg`. Reach for the smaller sizes (`xs`, `sm`) when buttons are packed into dense surfaces like toolbars, table rows, or inline controls, and the larger `lg` when you want a primary call to action to stand out as the focal point of a screen.

<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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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>

## Button Type

Inside a `Form`, buttons default to `type="submit"`, which triggers form submission on click. Set `button_type="button"` for actions that should not submit the form, like cancel or close buttons.

```python theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
from prefab_ui.components import Button, Form
from prefab_ui.actions.mcp import CallTool

with Form(on_submit=CallTool("save")):
    # ... inputs ...
    Button("Cancel", variant="outline", button_type="button")
    Button("Save")  # defaults to submit
```

The three standard HTML button types are available: `"submit"` (default in forms), `"button"` (no form behavior), and `"reset"` (clears the form).

## Disabled State

Set `disabled=True` to signal that an action is unavailable right now and to block clicks until conditions change. The button dims and stops responding to interaction, which is the right state for a submit button while a form is incomplete or an operation that can't run until a prerequisite is met.

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

    Button("Unavailable", disabled=True)
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "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="button_type" type="str | None" default="None">
    HTML button type: `"submit"` (default in forms), `"button"` (no form submit), or `"reset"`. Use `"button"` for cancel/close actions inside a Form.
  </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="on_click" type="Action | list[Action] | None" default="None">
    Action(s) to run when the button is clicked. Pass a list to sequence them; server actions like `CallTool` take their own `on_success`/`on_error` callbacks for follow-ups.
  </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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "Button",
  "id?": "string",
  "onMount?": "any",
  "label": "string (required)",
  "icon?": "string",
  "variant?": "default | destructive | outline | secondary | ghost | link | success | warning | info | string",
  "size?": "default | xs | sm | lg | icon | icon-xs | icon-sm | icon-lg",
  "buttonType?": "submit | button | reset",
  "disabled?": "boolean | string",
  "onClick?": "Action | Action[]",
  "cssClass?": "string"
}
```

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