---
name: card
title: Card
url: https://ui.frontic.com/components/ui/card.md
tier: ui
install: npx @frontic/ui add card
files:
  - components/ui/card/Card.vue
  - components/ui/card/CardAction.vue
  - components/ui/card/CardContent.vue
  - components/ui/card/CardDescription.vue
  - components/ui/card/CardFooter.vue
  - components/ui/card/CardHeader.vue
  - components/ui/card/CardImage.vue
  - components/ui/card/CardTitle.vue
  - components/ui/card/index.ts
dependencies:
  - class-variance-authority
  - reka-ui
---

# Card

Frames related content such as a product or an order, with header, title, description, action, image, content and footer parts.

## Install

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

Used by: [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), [Order Summary](https://ui.frontic.com/components/sections/order-summary.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 Card Minimal](https://ui.frontic.com/components/sections/product-card-minimal.md), [Product Options](https://ui.frontic.com/components/sections/product-options.md), [Promo Code](https://ui.frontic.com/components/sections/promo-code.md), [Recent Orders](https://ui.frontic.com/components/sections/recent-orders.md), [Return Request](https://ui.frontic.com/components/sections/return-request.md), [Reviews](https://ui.frontic.com/components/sections/reviews.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 Full](https://ui.frontic.com/components/templates/cart-full.md), [Checkout Page](https://ui.frontic.com/components/templates/checkout-page.md)

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

## Examples

```vue
<script setup lang="ts">
import { ClockIcon, MapPinIcon, PackageCheckIcon, PhoneIcon } from '@lucide/vue'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardImage, CardTitle } from '@/components/ui/card'
</script>

<template>
  <Card class="w-full max-w-sm">
    <CardImage>
      <img
        src="https://static.frontic.com/cdn-cgi/image/width=768,format=auto/ui/banners/mens-jackets.png"
        alt="A skier in a colour-block jacket in front of snowy mountains"
        class="aspect-video w-full object-cover"
      />
    </CardImage>
    <CardHeader>
      <CardTitle>Basecamp Innsbruck</CardTitle>
      <CardDescription>Maria-Theresien-Straße 18, 6020 Innsbruck</CardDescription>
      <CardAction>
        <Badge variant="success" size="sm">Open</Badge>
      </CardAction>
    </CardHeader>
    <CardContent>
      <ul class="flex flex-col gap-3">
        <li class="flex items-center gap-2">
          <ClockIcon class="size-4 shrink-0" data-icon />
          Open today until 19:00
        </li>
        <li class="flex items-center gap-2">
          <MapPinIcon class="size-4 shrink-0" data-icon />
          1.2 km away
        </li>
        <li class="flex items-center gap-2">
          <PackageCheckIcon class="size-4 shrink-0" data-icon />
          Click &amp; collect ready in 2 hours
        </li>
      </ul>
    </CardContent>
    <CardFooter class="gap-2">
      <Button as="a" href="tel:+43512123456" variant="outline" color="neutral" class="flex-1">
        <PhoneIcon data-icon="inline-start" />
        Call
      </Button>
      <Button as="a" href="#directions" class="flex-1">Directions</Button>
    </CardFooter>
  </Card>
</template>
```

The example also uses `badge` and `button`, which `add card` leaves out: `npx @frontic/ui add badge button`.

## Anatomy

```vue
<Card>
  <CardImage />
  <CardHeader>
    <CardTitle />
    <CardDescription />
    <CardAction />
  </CardHeader>
  <CardContent />
  <CardFooter />
</Card>
```

## API reference

### Card

Groups related content, such as a product or an order, into one framed block. Renders a `<div>`.

`data-slot="card"` · `Card.vue`

Styling: `card`, which extends [`panel`](https://ui.frontic.com/DESIGN.md#panel) and [`surface-inset`](https://ui.frontic.com/DESIGN.md#surface-inset). Change them there and every part that extends them 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `surface` | `'raised' \| 'bare'` | `'raised'` | Raised stands on its own with an edge, a shadow and an inset; bare sits flush inside another surface, a Card-rooted section inside a Card. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-surface` | `'raised' \| 'bare'` | Carries the `surface` prop. |

### CardAction

Holds a control placed at the end of the card header. Renders a `<div>`.

`data-slot="card-action"` · `CardAction.vue`

| 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardContent

Holds the main content of the card. Renders a `<div>`.

`data-slot="card-content"` · `CardContent.vue`

| 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardDescription

Shows secondary text below the card title. Renders a `<div>`.

`data-slot="card-description"` · `CardDescription.vue`

Styling: `card-description`, which extends [`part-description`](https://ui.frontic.com/DESIGN.md#part-description). 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardFooter

Holds the closing content of the card, such as status or buttons. Renders a `<div>`.

`data-slot="card-footer"` · `CardFooter.vue`

| 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardHeader

Groups the title, description and action at the top of the card. Renders a `<div>`.

`data-slot="card-header"` · `CardHeader.vue`

| 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardImage

Shows a picture across the top of the card. Renders a `<div>`.

`data-slot="card-image"` · `CardImage.vue`

| 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### CardTitle

Names what the card is about. Renders a `<div>`.

`data-slot="card-title"` · `CardTitle.vue`

Styling: `card-title`, which extends [`part-title`](https://ui.frontic.com/DESIGN.md#part-title). 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` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

## Styling

| Part | Recipe |
| --- | --- |
| `action` | [`card-action`](https://ui.frontic.com/DESIGN.md#card-action) |
| `default` | [`card`](https://ui.frontic.com/DESIGN.md#card) |
| `header` | [`card-header`](https://ui.frontic.com/DESIGN.md#card-header) |
| `content` | [`card-content`](https://ui.frontic.com/DESIGN.md#card-content) |
| `footer` | [`card-footer`](https://ui.frontic.com/DESIGN.md#card-footer) |
| `title` | [`card-title`](https://ui.frontic.com/DESIGN.md#card-title) |
| `description` | [`card-description`](https://ui.frontic.com/DESIGN.md#card-description) |

## Source

`components/ui/card/Card.vue`

```vue
<script lang="ts">
/** Groups related content, such as a product or an order, into one framed block. */
export default {}
</script>

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

const card = cva('fui-card group/card overflow-hidden has-[>img:first-child]:pt-0 has-[>[data-slot=card-image]:first-child]:pt-0', {
  variants: {
    surface: {
      raised: 'fui-card-raised',
      bare: 'fui-card-bare',
    },
  },
  defaultVariants: { surface: 'raised' },
})

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      /** Raised stands on its own with an edge, a shadow and an inset; bare sits flush inside another surface, a Card-rooted section inside a Card. */
      surface?: VariantProps<typeof card>['surface']
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div', surface: 'raised' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card" :data-surface="props.surface" :class="[card({ surface: props.surface }), props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardAction.vue`

```vue
<script lang="ts">
/** Holds a control placed at the end of the card header. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive
    :as="props.as"
    :as-child="props.asChild"
    data-slot="card-action"
    :class="['fui-card-action @sm/card-header:col-start-2 @sm/card-header:justify-self-end @sm/card-header:row-span-2 @sm/card-header:row-start-1', props.class]"
  >
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardContent.vue`

```vue
<script lang="ts">
/** Holds the main content of the card. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-content" :class="['fui-card-content', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardDescription.vue`

```vue
<script lang="ts">
/** Shows secondary text below the card title. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-description" :class="['fui-card-description', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardFooter.vue`

```vue
<script lang="ts">
/** Holds the closing content of the card, such as status or buttons. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-footer" :class="['fui-card-footer', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardHeader.vue`

```vue
<script lang="ts">
/** Groups the title, description and action at the top of the card. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-header" :class="['fui-card-header group/card-header @container/card-header auto-rows-min', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardImage.vue`

```vue
<script lang="ts">
/** Shows a picture across the top of the card. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-image" :class="['overflow-hidden', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/card/CardTitle.vue`

```vue
<script lang="ts">
/** Names what the card is about. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="card-title" :class="['fui-card-title', props.class]">
    <slot />
  </Primitive>
</template>
```

## API of the items the example uses

### Badge

[Full docs](https://ui.frontic.com/components/ui/badge.md) · `npx @frontic/ui add badge`

#### Badge

Marks an item with a short label such as new or sale. Renders a `<span>`.

`data-slot="badge"` · `Badge.vue`

| 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` | `'span'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `variant` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'error' \| 'primary' \| 'promo' \| 'discount' \| 'new' \| 'price'` | `'neutral'` | What the badge marks: a state (info, success, warning, error), a commerce label (promo, discount, new, price), the brand colour (primary) or nothing in particular (neutral). Each takes its own colour and form. |
| `size` | `'md' \| 'sm' \| 'lg'` | `'md'` | The badge's padding and text size: sm keeps the smallest text, md and lg take the caption style. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-variant` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'error' \| 'primary' \| 'promo' \| 'discount' \| 'new' \| 'price'` | Carries the `variant` prop. |

### Button

[Full docs](https://ui.frontic.com/components/ui/button.md) · `npx @frontic/ui add button`

#### 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. |
