---
name: spinner
title: Spinner
url: https://ui.frontic.com/components/ui/spinner.md
tier: ui
install: npx @frontic/ui add spinner
files:
  - components/ui/spinner/Spinner.vue
  - components/ui/spinner/index.ts
dependencies:
  - "@lucide/vue"
---

# Spinner

A turning loader that tells screen readers what is loading; inside a button it takes the icon slot and size.

## Install

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

npm packages: `@lucide/vue`

## Examples

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

<template>
  <!-- An add-to-cart button while the cart answers. -->
  <Button color="buy" disabled>
    <Spinner data-icon="inline-start" aria-hidden="true" />
    Adding to cart
  </Button>
</template>
```

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

## API reference

### Spinner

Shows that something is loading or in progress.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `label` | `string` | `'Loading'` | Read by screen readers while the spinner shows. |

## Styling

| Part | Recipe |
| --- | --- |
| `default` | [`spinner`](https://ui.frontic.com/DESIGN.md#spinner) |

## Source

`components/ui/spinner/Spinner.vue`

```vue
<script lang="ts">
/** Shows that something is loading or in progress. */
export default {}
</script>

<script setup lang="ts">
import { Loader2Icon } from '@lucide/vue'

import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes['class']
    /** Read by screen readers while the spinner shows. */
    label?: string
  }>(),
  { label: 'Loading' },
)
</script>

<template>
  <Loader2Icon role="status" :aria-label="props.label" :class="['fui-spinner animate-spin', props.class]" />
</template>
```

## API of the items the example uses

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