Primary actions with variants, text sizes, icon sizes, and a plain icon-only style.
Also known as: cta, action button, icon button, plain icon button, outline button, transparent outline
Install with the CLI, or copy the component source into your project.
Add button (npm)
1npx --yes -p @default-file/ui df-ui add button
Primary action button.
All visual variants.
Link variant underline on hover. Set underline to false to keep the label plain.
Outline only. Set transparent to drop the resting fill.
Text button sizes from xs to 2xl.
Override padding, height, width, type size, line height, font, and radius on one button. Props write --df-button-* on the host. Size still supplies defaults when a prop is omitted.
Square icon-only controls from icon-2xs to icon-2xl. These keep the standard control plate. Use the Plain icon demo for chrome without a resting plate.
Icon-only chrome with no resting plate. The hit box matches the glyph; hover and focus expand a soft pad without layout shift. Pair with icon-2xs to icon-2xl and an aria-label. Prefer over ghost on media and dense overlays.
Icon only control, plus leading and trailing icons on text buttons including xs.
Leading and trailing accept any node: badge, counter, close, avatar.
Muted appearance. Spinner in the leading or trailing icon slot. Works on every variant except link. Icon only sizes replace the icon.
Solid appearance. Background stays at full strength, the label fades, and the Spinner stays fully visible.
Corner count with badgeSide end and badgePosition edge (defaults). Sits on the trailing top corner. Badge contrast flips on the filled default variant.
Corner count with badgeSide start. Places the badge on the leading top corner instead of the usual trailing side.
Corner count with badgePosition inset. Pulls the badge a notch inside the button on the trailing side.
Primary actions with variants, text and icon sizes, optional leading or trailing content, loading state, and a corner count badge. plain is the icon-only variant with no resting plate. Use transparent on outline to drop the resting fill.
| Prop | Type | Default | Notes |
|---|---|---|---|
| variant | "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | "plain" | "default" | Visual style of the button. plain is icon-only chrome with no resting plate; hover and focus expand a soft pad around the glyph without shifting layout. Use ghost for labeled transparent actions on UI chrome. Prefer plain on media, gradients, and dense overlays. Give plain buttons an aria-label. link is inline text with no control height or horizontal padding. On outline, set transparent to drop the resting fill. |
| size | "default" | "xs" | "sm" | "lg" | "xl" | "2xl" | "icon" | "icon-2xs" | "icon-xs" | "icon-sm" | "icon-lg" | "icon-xl" | "icon-2xl" | "default" | Text sizes use padding, type size, and line height (xs to 2xl). Height follows those tokens unless you set height. Icon sizes are square controls (icon-2xs to icon-2xl) on the form control height tokens. Override padding, size, type, font, and radius with chrome props or --df-button-* variables. plain requires an icon size; the resting box matches the glyph for that step. If plain is paired with a text size, size falls back to icon-xs. |
| underline | boolean | true | Link variant only. When true, show underline on hover. Set false to keep the label plain on hover. |
| transparent | boolean | false | Outline variant only. When true, drop the resting fill (data-transparent). Theme the filled plate with --df-button-outline-fill. Hover and expanded washes stay for affordance. Ignored on other variants. |
| leading | ReactNode | - | Content before the label, such as an icon. |
| trailing | ReactNode | - | Content after the label, such as an icon or badge. |
| loading | boolean | false | Shows a Spinner in the icon area, keeps the label, and disables the control. Unsupported on the link variant. Supported on plain icon sizes. |
| loadingPlacement | "leading" | "trailing" | "leading" | Which icon slot shows the Spinner while loading. Ignored for icon-only sizes, which replace the icon child. |
| loadingAppearance | "muted" | "solid" | "muted" | muted fades the whole control like disabled. solid keeps the default background, fades the label only, and leaves the Spinner at full opacity. |
| badge | number | string | - | Corner count badge anchored to the top end of the button. Count ink is optically centered to cap height with text-box when available, and a 1cap line box otherwise. Hidden when empty, null, or 0. Include the count in aria-label for icon buttons. |
| badgeVariant | "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | - | Badge visual style. Defaults to secondary on the default button variant, otherwise default, so the count stays readable on dark fills. |
| badgePosition | "edge" | "inset" | "edge" | edge sits on the corner. inset pulls the badge a notch inside the button. |
| badgeSide | "start" | "end" | "end" | Which top corner hosts the badge. end is the trailing side (right in left to right layouts). start is the leading side. |
| disabled | boolean | - | Disables the button. |
| className | string | - | Additional styles. |
String props write --df-button-* on the host. Prefer token expressions such as var(--df-text-sm), var(--df-font-sans), var(--radius-md), or calc(4 * var(--spacing-unit)). Size still supplies defaults when a prop is omitted. On dfButtonClass hosts, pass the same values through dfButtonChromeStyle into style.
| Prop | Type | Default | Notes |
|---|---|---|---|
| padding | string | - | Padding on all sides. Sets --df-button-padding-block-start, --df-button-padding-block-end, --df-button-padding-inline-start, and --df-button-padding-inline-end. |
| paddingX | string | - | Horizontal padding. Sets --df-button-padding-inline-start and --df-button-padding-inline-end. Overrides padding on those sides. |
| paddingY | string | - | Vertical padding. Sets --df-button-padding-block-start and --df-button-padding-block-end. Overrides padding on those sides. |
| paddingTop | string | - | Top padding. Sets --df-button-padding-block-start and wins over paddingY and padding. |
| paddingRight | string | - | Trailing-edge padding. Sets --df-button-padding-inline-end and wins over paddingX and padding. |
| paddingBottom | string | - | Bottom padding. Sets --df-button-padding-block-end and wins over paddingY and padding. |
| paddingLeft | string | - | Leading-edge padding. Sets --df-button-padding-inline-start and wins over paddingX and padding. |
| height | string | - | Control height. Default auto so height follows padding and line height. Sets --df-button-height. |
| width | string | - | Control width. Default auto so width follows content and padding. Sets --df-button-width. |
| fontSize | string | - | Label type size. Prefer type tokens such as var(--df-text-sm). Sets --df-button-font-size. |
| lineHeight | string | - | Label line height. Prefer leading tokens such as var(--df-leading-5). Sets --df-button-line-height. |
| fontFamily | string | - | Label font family. Prefer family tokens such as var(--df-font-sans) or var(--df-font-mono). Sets --df-button-font-family. |
| fontWeight | string | - | Label font weight. Prefer weight tokens such as var(--df-font-weight-medium). Sets --df-button-font-weight. |
| radius | string | - | Corner radius. Prefer radius tokens such as var(--radius-md). Default is --radius-4xl. Sets --df-button-radius. |
Class helper for applying button styles to a host that is not a button.
| Prop | Type | Default | Notes |
|---|---|---|---|
| dfButtonClass | (opts?: { variant?, size?, className? }) => string | - | Builds the same class string Button uses internally. Resolves plain with a non-icon size to icon-xs, matching Button. For link hosts, set the underline data attribute to hover or none to match the underline prop. For outline hosts without a resting fill, set data-transparent. |
| dfButtonChromeStyle | (opts?: ButtonChromeProps) => CSSProperties | - | Writes the same --df-button-* variables the chrome props set on Button. Merge into style on a dfButtonClass host. |
Theme defaults live on :root. Override these globally or on a local host.
| Token | Type | Default | Notes |
|---|---|---|---|
| --spacing-unit | CSS length | 0.25rem | Base unit for padding, gap, and icon button size. |
| --primary | CSS color | var(--df-neutral-850, var(--df-neutral-900)) | Default variant fill. |
| --primary-foreground | CSS color | var(--df-neutral-0) | Default variant label. |
| --secondary | CSS color | var(--df-neutral-50) | Secondary variant fill. |
| --secondary-foreground | CSS color | var(--df-neutral-850, var(--df-neutral-900)) | Secondary variant label. |
| --destructive | CSS color | oklch(0.577 0.245 27.325) | Destructive variant fill. |
| --border | CSS color | var(--df-neutral-100) | Outline variant border. |
| --df-button-outline-fill | CSS color | color-mix(in oklch, var(--input) 30%, var(--background)) | Outline variant resting fill from the theme tables (:root and .dark). Overridden when transparent is true. |
| --df-button-outline-fill-hover | CSS color | color-mix(in oklch, var(--input) 50%, var(--background)) | Outline variant hover fill from the theme tables (:root and .dark). |
| --muted | CSS color | var(--df-neutral-50) | Ghost variant hover fill. |
| --ring | CSS color | var(--df-neutral-400) | Focus ring color. |
| --df-button-plain-hover-outset | CSS length | calc(1 * var(--spacing-unit)) | How far the plain icon hover pad expands beyond the glyph. |
| --df-button-plain-hover-fill | CSS color | color-mix(in oklch, var(--foreground) 14%, transparent) | Plain icon hover pad fill. |
| --df-button-plain-hover-radius | CSS length | var(--radius-md) | Corner radius of the plain icon hover pad. |
| --df-affordance-size-2xs | CSS length | calc(2 * var(--spacing-unit)) | Glyph size for icon-2xs and plain icon-2xs. |
| --df-press-offset | CSS length | 1px | Active press translate distance. |
| --df-underline-offset | CSS length | 4px | Link variant underline offset. |
| --df-button-radius | CSS length | var(--radius-4xl) | Corner radius. Default is --radius-4xl. Set by the radius chrome prop. |
| --radius-4xl | CSS length | calc(var(--radius) * 2.6) | Default corner radius. |
| --df-button-badge-size | CSS length | calc(4 * var(--spacing-unit)) | Corner badge height and minimum width. |
| --df-button-badge-pad-inline | CSS length | calc(1 * var(--spacing-unit)) | Horizontal padding inside the corner badge for longer counts. |
| --df-button-badge-inset | CSS length | calc(1 * var(--spacing-unit)) | Offset used when badgePosition is inset. |
| --df-button-font-family | CSS font-family | var(--df-font-sans) | Label font family. |
| --df-button-font-weight | CSS font-weight | var(--df-font-weight-medium) | Label font weight. |
| --df-button-height-md | CSS length | auto | Default text size height. Auto follows padding and line height. Same pattern on --df-button-height-xs to --df-button-height-2xl. |
| --df-button-width-md | CSS length | auto | Default text size width. Auto follows content and padding. Same pattern on --df-button-width-xs to --df-button-width-2xl. |
| --df-button-font-size-xs | CSS length | var(--df-text-xs) | xs text size. Maps to --df-text-xs (0.75rem). |
| --df-button-font-size-sm | CSS length | var(--df-text-sm) | sm text size. Maps to --df-text-sm (0.875rem). |
| --df-button-font-size-md | CSS length | var(--df-text-sm) | Default text size. Maps to --df-text-sm (0.875rem). |
| --df-button-font-size-lg | CSS length | var(--df-text-sm) | lg text size. Maps to --df-text-sm (0.875rem). |
| --df-button-font-size-xl | CSS length | var(--df-text-sm) | xl text size. Maps to --df-text-sm (0.875rem). |
| --df-button-font-size-2xl | CSS length | var(--df-text-sm) | 2xl text size. Maps to --df-text-sm (0.875rem). |
| --df-button-line-height-xs | CSS length | var(--df-leading-4) | xs line height. Maps to --df-leading-4 (1rem). |
| --df-button-line-height-sm | CSS length | var(--df-leading-4) | sm line height. Maps to --df-leading-4 (1rem). |
| --df-button-line-height-md | CSS length | var(--df-leading-5) | Default line height. Maps to --df-leading-5 (1.25rem). |
| --df-button-line-height-lg | CSS length | var(--df-leading-5) | lg line height. Maps to --df-leading-5 (1.25rem). |
| --df-button-line-height-xl | CSS length | var(--df-leading-5) | xl line height. Maps to --df-leading-5 (1.25rem). |
| --df-button-line-height-2xl | CSS length | var(--df-leading-5) | 2xl line height. Maps to --df-leading-5 (1.25rem). |
| --df-button-padding-block-xs | CSS length | calc(1 * var(--spacing-unit)) | xs vertical padding. One spacing unit (4px). |
| --df-button-padding-block-sm | CSS length | calc(2 * var(--spacing-unit)) | sm vertical padding. Two spacing units (8px). |
| --df-button-padding-block-md | CSS length | calc(2 * var(--spacing-unit)) | Default vertical padding. Two spacing units (8px). |
| --df-button-padding-block-lg | CSS length | calc(2.5 * var(--spacing-unit)) | lg vertical padding. Two and a half spacing units (10px). |
| --df-button-padding-block-xl | CSS length | calc(3 * var(--spacing-unit)) | xl vertical padding. Three spacing units (12px). |
| --df-button-padding-block-2xl | CSS length | calc(3.5 * var(--spacing-unit)) | 2xl vertical padding. Three and a half spacing units (14px). |
| --df-button-padding-inline-xs | CSS length | calc(2.5 * var(--spacing-unit)) | xs horizontal padding. Two and a half spacing units (10px). |
| --df-button-padding-inline-sm | CSS length | calc(4 * var(--spacing-unit)) | sm horizontal padding. Four spacing units (1rem). |
| --df-button-padding-inline-md | CSS length | calc(4 * var(--spacing-unit)) | Default horizontal padding. Four spacing units (1rem). |
| --df-button-padding-inline-lg | CSS length | calc(5 * var(--spacing-unit)) | lg horizontal padding. Five spacing units (1.25rem). |
| --df-button-padding-inline-xl | CSS length | calc(6 * var(--spacing-unit)) | xl horizontal padding. Six spacing units (1.5rem). |
| --df-button-padding-inline-2xl | CSS length | calc(7 * var(--spacing-unit)) | 2xl horizontal padding. Seven spacing units (1.75rem). |
| --df-button-padding-inline-start | CSS length | var(--df-button-padding-inline-md) | Default text size padding on the leading edge. Aliases --df-button-padding-inline-md. |
| --df-button-padding-inline-end | CSS length | var(--df-button-padding-inline-md) | Default text size padding on the trailing edge. Aliases --df-button-padding-inline-md. |
| --df-button-padding-inline-icon-xs | CSS length | calc(2 * var(--spacing-unit)) | xs icon-adjacent inline padding. Two spacing units (8px). |
| --df-button-padding-inline-icon-sm | CSS length | calc(3 * var(--spacing-unit)) | sm icon-adjacent inline padding. Three spacing units (0.75rem). |
| --df-button-padding-inline-icon-md | CSS length | calc(3 * var(--spacing-unit)) | Default icon-adjacent inline padding. Three spacing units (0.75rem). |
| --df-button-padding-inline-icon-lg | CSS length | calc(4 * var(--spacing-unit)) | lg icon-adjacent inline padding. Four spacing units (1rem). |
| --df-button-padding-inline-icon-xl | CSS length | calc(5 * var(--spacing-unit)) | xl icon-adjacent inline padding. Five spacing units (1.25rem). |
| --df-button-padding-inline-icon-2xl | CSS length | calc(6 * var(--spacing-unit)) | 2xl icon-adjacent inline padding. Six spacing units (1.5rem). |
| --df-button-padding-inline-start-icon | CSS length | var(--df-button-padding-inline-icon-md) | Default text size leading-edge padding when a leading icon is present. Aliases --df-button-padding-inline-icon-md. |
| --df-button-padding-inline-end-icon | CSS length | var(--df-button-padding-inline-icon-md) | Default text size trailing-edge padding when a trailing icon is present. Aliases --df-button-padding-inline-icon-md. |
| --z-raised | number | 1 | Stacking level for the corner badge. |
| --df-label-line-height | CSS line-height | var(--df-leading-none) | Line box for label flex centering. Defaults to --df-leading-none. When text-box is unavailable and the cap unit is supported, the kit sets this to 1cap so flex centering matches cap-height ink. |
| --df-corner-shape | CSS corner-shape | var(--df-corner-shape-round) | Theme corner curve for all kit chrome. round = circular arcs; smooth = continuous squircle. Set with df-ui init --corner-shape, or override on :root. Default round. |