---
name: button
title: Button
url: https://ui.frontic.com/components/ui/button.md
tier: ui
install: npx @frontic/ui add button
files:
  - components/ui/button/Button.vue
  - components/ui/button/index.ts
dependencies:
  - class-variance-authority
  - reka-ui
---

# Button

Triggers an action such as adding to the cart: solid, outline, soft, ghost or link, in primary, neutral, destructive, inverse and the commerce colours buy and checkout.

## Install

```sh
npx @frontic/ui add button
```

Used by: [Alert Dialog](https://ui.frontic.com/components/ui/alert-dialog.md), [Carousel](https://ui.frontic.com/components/ui/carousel.md), [Dialog](https://ui.frontic.com/components/ui/dialog.md), [Filter](https://ui.frontic.com/components/ui/filter.md), [Input Group](https://ui.frontic.com/components/ui/input-group.md), [Pagination](https://ui.frontic.com/components/ui/pagination.md), [Sheet](https://ui.frontic.com/components/ui/sheet.md), [Sidebar](https://ui.frontic.com/components/ui/sidebar.md), [Account Access](https://ui.frontic.com/components/sections/account-access.md), [Cart Summary](https://ui.frontic.com/components/sections/cart-summary.md), [Delivery Slot](https://ui.frontic.com/components/sections/delivery-slot.md), [Filters](https://ui.frontic.com/components/sections/filters.md), [Footer Brand](https://ui.frontic.com/components/sections/footer-brand.md), [Footer Rich](https://ui.frontic.com/components/sections/footer-rich.md), [Navigation Shop](https://ui.frontic.com/components/sections/navigation-shop.md), [Order Tracking](https://ui.frontic.com/components/sections/order-tracking.md), [Payment Method](https://ui.frontic.com/components/sections/payment-method.md), [Product Card Basic](https://ui.frontic.com/components/sections/product-card-basic.md), [Product Card Featured](https://ui.frontic.com/components/sections/product-card-featured.md), [Product Card Gallery](https://ui.frontic.com/components/sections/product-card-gallery.md), [Product Card Horizontal](https://ui.frontic.com/components/sections/product-card-horizontal.md), [Product Card Hover](https://ui.frontic.com/components/sections/product-card-hover.md), [Product Options](https://ui.frontic.com/components/sections/product-options.md), [Recent Orders](https://ui.frontic.com/components/sections/recent-orders.md), [Return Request](https://ui.frontic.com/components/sections/return-request.md), [Review Cards](https://ui.frontic.com/components/sections/review-cards.md), [Reviews](https://ui.frontic.com/components/sections/reviews.md), [Search Suggestions](https://ui.frontic.com/components/sections/search-suggestions.md), [Settings](https://ui.frontic.com/components/sections/settings.md), [Shipping Address](https://ui.frontic.com/components/sections/shipping-address.md), [Sign In](https://ui.frontic.com/components/sections/sign-in.md), [Team Members](https://ui.frontic.com/components/sections/team-members.md), [Cart Compact](https://ui.frontic.com/components/templates/cart-compact.md), [Cart Full](https://ui.frontic.com/components/templates/cart-full.md), [Cart Item Compact](https://ui.frontic.com/components/templates/cart-item-compact.md), [Cart Item Detailed](https://ui.frontic.com/components/templates/cart-item-detailed.md), [Cart Minimal](https://ui.frontic.com/components/templates/cart-minimal.md), [Category Filter](https://ui.frontic.com/components/templates/category-filter.md), [Category Grid](https://ui.frontic.com/components/templates/category-grid.md), [Checkout Page](https://ui.frontic.com/components/templates/checkout-page.md), [Filter Sheet](https://ui.frontic.com/components/templates/filter-sheet.md), [Filter Sidebar](https://ui.frontic.com/components/templates/filter-sidebar.md), [Filter Toolbar](https://ui.frontic.com/components/templates/filter-toolbar.md), [Header Centered](https://ui.frontic.com/components/templates/header-centered.md), [Header Shop](https://ui.frontic.com/components/templates/header-shop.md)

npm packages: `class-variance-authority`, `reka-ui`

## Examples

```vue
<script setup lang="ts">
import { Button } from '@/components/ui/button'
</script>

<template>
  <Button color="buy">Add to cart</Button>
</template>
```

## API reference

### Button

Lets the user trigger an action, such as adding a product to the cart. Renders a `<button>`.

`data-slot="button"` · `Button.vue`

Styling: `button`, which extends [`action`](https://ui.frontic.com/DESIGN.md#action). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'button'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `variant` | `'solid' \| 'outline' \| 'soft' \| 'ghost' \| 'link'` | `'solid'` | The visual style: a filled, outlined, tinted, background-free or text-link button. |
| `color` | `'neutral' \| 'primary' \| 'destructive' \| 'buy' \| 'checkout' \| 'inverse'` | `'primary'` | The colour role, e.g. primary for the brand colour, buy for add-to-cart, checkout for the checkout step, destructive for removing. |
| `size` | `'md' \| 'xs' \| 'sm' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon-md' \| 'icon-lg'` | `'md'` | The button's height and padding; the `icon-*` sizes make a square, icon-only button. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-color` | `'neutral' \| 'primary' \| 'destructive' \| 'buy' \| 'checkout' \| 'inverse'` | Carries the `color` prop. |
| `data-size` | `'md' \| 'xs' \| 'sm' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon-md' \| 'icon-lg'` | Carries the `size` prop. |
| `data-variant` | `'solid' \| 'outline' \| 'soft' \| 'ghost' \| 'link'` | Carries the `variant` prop. |

## Styling

| Part | Recipe |
| --- | --- |
| `default` | [`button`](https://ui.frontic.com/DESIGN.md#button) |
| `focus-ring` | [`focus-ring`](https://ui.frontic.com/DESIGN.md#focus-ring) |
| `disabled` | [`disabled`](https://ui.frontic.com/DESIGN.md#disabled) |
| `invalid` | [`invalid`](https://ui.frontic.com/DESIGN.md#invalid) |

States with a look of their own: hover, focus, disabled and invalid.

## Source

`components/ui/button/Button.vue`

```vue
<script lang="ts">
/** Lets the user trigger an action, such as adding a product to the cart. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cva, type VariantProps } from 'class-variance-authority'
import { Primitive } from 'reka-ui'

const button = cva(
  'fui-button group/button whitespace-nowrap bg-clip-padding outline-none transition-all select-none focus-visible:fui-focus-ring aria-invalid:fui-invalid disabled:pointer-events-none disabled:fui-disabled aria-disabled:pointer-events-none aria-disabled:fui-disabled **:data-icon:pointer-events-none **:data-icon:shrink-0',
  {
    variants: {
      variant: {
        solid: 'fui-button-solid',
        outline: 'fui-button-outline',
        soft: 'fui-button-soft',
        ghost: 'fui-button-ghost',
        link: 'fui-button-link',
      },
      color: {
        primary: 'fui-button-primary',
        neutral: 'fui-button-neutral',
        destructive: 'fui-button-destructive',
        buy: 'fui-button-buy',
        checkout: 'fui-button-checkout',
        inverse: 'fui-button-inverse',
      },
      size: {
        xs: 'fui-button-xs',
        sm: 'fui-button-sm',
        md: 'fui-button-md',
        lg: 'fui-button-lg',
        'icon-xs': 'fui-button-icon-xs',
        'icon-sm': 'fui-button-icon-sm',
        'icon-md': 'fui-button-icon-md',
        'icon-lg': 'fui-button-icon-lg',
      },
    },
    defaultVariants: { variant: 'solid', color: 'primary', size: 'md' },
  },
)

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      /** The visual style: a filled, outlined, tinted, background-free or text-link button. */
      variant?: VariantProps<typeof button>['variant']
      /** The colour role, e.g. primary for the brand colour, buy for add-to-cart, checkout for the checkout step, destructive for removing. */
      color?: VariantProps<typeof button>['color']
      /** The button's height and padding; the `icon-*` sizes make a square, icon-only button. */
      size?: VariantProps<typeof button>['size']
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'button', variant: 'solid', color: 'primary', size: 'md' },
)
</script>

<template>
  <Primitive
    data-slot="button"
    :data-variant="props.variant"
    :data-color="props.color"
    :data-size="props.size"
    :as="props.as"
    :as-child="props.asChild"
    :type="props.as === 'button' && !props.asChild ? 'button' : undefined"
    :class="[button({ variant: props.variant, color: props.color, size: props.size }), props.class]"
  >
    <slot />
  </Primitive>
</template>
```
