Button
Usage
Label
Use the default slot to set the label of the Button.
<template>
  <UButton>Button</UButton>
</template>
You can achieve the same result by using the label prop.
<template>
  <UButton label="Button" />
</template>
Link
You can pass any property from the Link component such as to, target, etc.
<template>
  <UButton to="https://github.com/nuxt/ui" target="_blank">Button</UButton>
</template>
Color
Use the color prop to change the color of the Button.
<template>
  <UButton color="neutral">Button</UButton>
</template>
Variant
Use the variant prop to change the variant of the Button.
<template>
  <UButton color="neutral" variant="outline">Button</UButton>
</template>
Size
Use the size prop to change the size of the Button.
<template>
  <UButton size="xl">Button</UButton>
</template>
Icon
Use the icon prop to show an Icon inside the Button.
<template>
  <UButton icon="i-lucide-rocket">Button</UButton>
</template>
Use the leading and trailing props to set the icon position or the leading-icon and trailing-icon props to set a different icon for each position.
<template>
  <UButton trailing-icon="i-lucide-arrow-right">Button</UButton>
</template>
The label as prop or slot is optional so you can use the Button as an icon-only button.
<template>
  <UButton icon="i-lucide-search" />
</template>
Avatar
Use the avatar prop to show an Avatar inside the Button.
<template>
  <UButton
    :avatar="{
      src: 'https://github.com/nuxt.png'
    }"
    color="neutral"
    variant="outline"
  >
    Button
  </UButton>
</template>
The label as prop or slot is optional so you can use the Button as an avatar-only button.
<template>
  <UButton
    :avatar="{
      src: 'https://github.com/nuxt.png'
    }"
    color="neutral"
    variant="outline"
  />
</template>
Loading
Use the loading prop to show a loading icon and disable the Button.
<template>
  <UButton loading>Button</UButton>
</template>
Use the loading-auto prop to show the loading icon automatically while the @click promise is pending.
<script setup lang="ts">
async function onClick() {
  return new Promise<void>(res => setTimeout(res, 1000))
}
</script>
<template>
  <UButton loading-auto @click="onClick">
    Button
  </UButton>
</template>
This also works with the Form component.
<script setup lang="ts">
const state = reactive({ fullName: '' })
async function onSubmit() {
  return new Promise<void>(res => setTimeout(res, 1000))
}
async function validate(data: Partial<typeof state>) {
  if (!data.fullName?.length) return [{ name: 'fullName', message: 'Required' }]
  return []
}
</script>
<template>
  <UForm :state="state" :validate="validate" @submit="onSubmit">
    <UFormField name="fullName" label="Full name">
      <UInput v-model="state.fullName" />
    </UFormField>
    <UButton type="submit" class="mt-2" loading-auto>
      Submit
    </UButton>
  </UForm>
</template>
Loading Icon
Use the loading-icon prop to customize the loading icon. Defaults to i-lucide-refresh-ccw.
<template>
  <UButton loading loading-icon="i-lucide-repeat-2">Button</UButton>
</template>
Disabled
Use the disabled prop to disable the Button.
<template>
  <UButton disabled>Button</UButton>
</template>
Examples
class prop
Use the class prop to override the base styles of the Button.
<template>
  <UButton class="font-bold rounded-full">Button</UButton>
</template>
ui prop
Use the ui prop to override the slots styles of the Button.
<template>
  <UButton
    icon="i-lucide-rocket"
    color="neutral"
    variant="outline"
    :ui="{
      leadingIcon: 'text-[var(--ui-primary)]'
    }"
  >
    Button
  </UButton>
</template>
API
Props
| Prop | Default | Type | 
|---|---|---|
| as | 
 | 
 The element or component this component should render as when not a link. | 
| label | 
 | |
| color | 
 | 
 | 
| variant | 
 | 
 | 
| size | 
 | 
 | 
| square | 
 Render the button with equal padding on all sides. | |
| block | 
 Render the button full width. | |
| loadingAuto | 
 Set loading state automatically based on the  | |
| icon | 
 Display an icon based on the  | |
| avatar | 
 Display an avatar on the left side. | |
| leading | 
 When  | |
| leadingIcon | 
 Display an icon on the left side. | |
| trailing | 
 When  | |
| trailingIcon | 
 Display an icon on the right side. | |
| loading | 
 When  | |
| loadingIcon | 
 | 
 The icon when the  | 
| type | 
 | 
 The type of the button when not a link. | 
| disabled | 
 | |
| target | 
 Where to display the linked URL, as the name for a browsing context. | |
| to | 
 Route Location the link should navigate to when clicked on. | |
| active | 
 Force the link to be active independent of the current route. | |
| ui | 
 | 
Slots
| Slot | Type | 
|---|---|
| leading | 
 | 
| default | 
 | 
| trailing | 
 | 
Theme
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        base: [
          'rounded-[calc(var(--ui-radius)*1.5)] font-medium inline-flex items-center focus:outline-none disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75',
          'transition-colors'
        ],
        label: 'truncate',
        leadingIcon: 'shrink-0',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        trailingIcon: 'shrink-0'
      },
      variants: {
        buttonGroup: {
          horizontal: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none',
          vertical: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none'
        },
        color: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          solid: '',
          outline: '',
          soft: '',
          subtle: '',
          ghost: '',
          link: ''
        },
        size: {
          xs: {
            base: 'px-2 py-1 text-xs gap-1',
            leadingIcon: 'size-4',
            leadingAvatarSize: '3xs',
            trailingIcon: 'size-4'
          },
          sm: {
            base: 'px-2.5 py-1.5 text-xs gap-1.5',
            leadingIcon: 'size-4',
            leadingAvatarSize: '3xs',
            trailingIcon: 'size-4'
          },
          md: {
            base: 'px-2.5 py-1.5 text-sm gap-1.5',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs',
            trailingIcon: 'size-5'
          },
          lg: {
            base: 'px-3 py-2 text-sm gap-2',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs',
            trailingIcon: 'size-5'
          },
          xl: {
            base: 'px-3 py-2 text-base gap-2',
            leadingIcon: 'size-6',
            leadingAvatarSize: 'xs',
            trailingIcon: 'size-6'
          }
        },
        block: {
          true: {
            base: 'w-full justify-center',
            leadingAvatarSize: 'xs',
            trailingIcon: 'ms-auto'
          }
        },
        square: {
          true: ''
        },
        leading: {
          true: ''
        },
        trailing: {
          true: ''
        },
        loading: {
          true: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: 'solid',
          class: 'text-[var(--ui-bg)] bg-[var(--ui-primary)] hover:bg-[var(--ui-primary)]/75 disabled:bg-[var(--ui-primary)] aria-disabled:bg-[var(--ui-primary)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ui-primary)]'
        },
        {
          color: 'primary',
          variant: 'outline',
          class: 'ring ring-inset ring-[var(--ui-primary)]/50 text-[var(--ui-primary)] hover:bg-[var(--ui-primary)]/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]'
        },
        {
          color: 'primary',
          variant: 'soft',
          class: 'text-[var(--ui-primary)] bg-[var(--ui-primary)]/10 hover:bg-[var(--ui-primary)]/15 focus-visible:bg-[var(--ui-primary)]/15 disabled:bg-[var(--ui-primary)]/10 aria-disabled:bg-[var(--ui-primary)]/10'
        },
        {
          color: 'primary',
          variant: 'subtle',
          class: 'text-[var(--ui-primary)] ring ring-inset ring-[var(--ui-primary)]/25 bg-[var(--ui-primary)]/10 hover:bg-[var(--ui-primary)]/15 disabled:bg-[var(--ui-primary)]/10 aria-disabled:bg-[var(--ui-primary)]/10 focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]'
        },
        {
          color: 'primary',
          variant: 'ghost',
          class: 'text-[var(--ui-primary)] hover:bg-[var(--ui-primary)]/10 focus-visible:bg-[var(--ui-primary)]/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent'
        },
        {
          color: 'primary',
          variant: 'link',
          class: 'text-[var(--ui-primary)] hover:text-[var(--ui-primary)]/75 disabled:text-[var(--ui-primary)] aria-disabled:text-[var(--ui-primary)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--ui-primary)]'
        },
        {
          color: 'neutral',
          variant: 'solid',
          class: 'text-[var(--ui-bg)] bg-[var(--ui-bg-inverted)] hover:bg-[var(--ui-bg-inverted)]/90 disabled:bg-[var(--ui-bg-inverted)] aria-disabled:bg-[var(--ui-bg-inverted)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ui-border-inverted)]'
        },
        {
          color: 'neutral',
          variant: 'outline',
          class: 'ring ring-inset ring-[var(--ui-border-accented)] text-[var(--ui-text)] bg-[var(--ui-bg)] hover:bg-[var(--ui-bg-elevated)] disabled:bg-[var(--ui-bg)] aria-disabled:bg-[var(--ui-bg)] focus-visible:ring-2 focus-visible:ring-[var(--ui-border-inverted)]'
        },
        {
          color: 'neutral',
          variant: 'soft',
          class: 'text-[var(--ui-text)] bg-[var(--ui-bg-elevated)] hover:bg-[var(--ui-bg-accented)]/75 focus-visible:bg-[var(--ui-bg-accented)]/75 disabled:bg-[var(--ui-bg-elevated)] aria-disabled:bg-[var(--ui-bg-elevated)]'
        },
        {
          color: 'neutral',
          variant: 'subtle',
          class: 'ring ring-inset ring-[var(--ui-border-accented)] text-[var(--ui-text)] bg-[var(--ui-bg-elevated)] hover:bg-[var(--ui-bg-accented)]/75 disabled:bg-[var(--ui-bg-elevated)] aria-disabled:bg-[var(--ui-bg-elevated)] focus-visible:ring-2 focus-visible:ring-[var(--ui-border-inverted)]'
        },
        {
          color: 'neutral',
          variant: 'ghost',
          class: 'text-[var(--ui-text)] hover:bg-[var(--ui-bg-elevated)] focus-visible:bg-[var(--ui-bg-elevated)] hover:disabled:bg-transparent dark:hover:disabled:bg-transparent hover:aria-disabled:bg-transparent dark:hover:aria-disabled:bg-transparent'
        },
        {
          color: 'neutral',
          variant: 'link',
          class: 'text-[var(--ui-text-muted)] hover:text-[var(--ui-text)] disabled:text-[var(--ui-text-muted)] aria-disabled:text-[var(--ui-text-muted)] focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-[var(--ui-border-inverted)]'
        },
        {
          size: 'xs',
          square: true,
          class: 'p-1'
        },
        {
          size: 'sm',
          square: true,
          class: 'p-1.5'
        },
        {
          size: 'md',
          square: true,
          class: 'p-1.5'
        },
        {
          size: 'lg',
          square: true,
          class: 'p-2'
        },
        {
          size: 'xl',
          square: true,
          class: 'p-2'
        },
        {
          loading: true,
          leading: true,
          class: {
            leadingIcon: 'animate-spin'
          }
        },
        {
          loading: true,
          leading: false,
          trailing: true,
          class: {
            trailingIcon: 'animate-spin'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        variant: 'solid',
        size: 'md'
      }
    }
  }
})