Components

Button

A button element that can act as a link or trigger an action.

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>

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="gray">Button</UButton>
</template>

Variant

Use the variant prop to change the variant of the Button.

<template>
  <UButton color="gray" 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-heroicons-rocket-launch">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-heroicons-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-heroicons-magnifying-glass" />
</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-heroicons-arrow-path-20-solid.

<template>
  <UButton loading loading-icon="i-heroicons-arrow-path-rounded-square">Button</UButton>
</template>
You can customize this icon globally in your app.config.ts under ui.icons.loading key.

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-heroicons-rocket-launch"
    color="gray"
    variant="outline"
    :ui="{
      leadingIcon: 'text-primary-500 dark:text-primary-400'
    }"
  >
    Button
  </UButton>
</template>

API

Props

Prop Default Type
as

'button'

any

The element or component this component should render as when not a link.

label

string

color

primary

"error" | "primary" | "red" | "orange" | "amber" | "yellow" | "lime" | "green" | "emerald" | "teal" | "cyan" | "sky" | "blue" | "indigo" | "violet" | "purple" | "fuchsia" | "pink" | "rose" | "gray"

variant

solid

"solid" | "outline" | "soft" | "subtle" | "ghost" | "link"

size

md

"md" | "xs" | "sm" | "lg" | "xl"

square

boolean

Render the button with equal padding on all sides.

block

boolean

Render the button full width.

loadingAuto

boolean

Set loading state automatically based on the @click promise state

icon

string

Display an icon based on the leading and trailing props.

leading

boolean

When true, the icon will be displayed on the left side.

leadingIcon

string

Display an icon on the left side.

trailing

boolean

When true, the icon will be displayed on the right side.

trailingIcon

string

Display an icon on the right side.

loading

boolean

When true, the loading icon will be displayed.

loadingIcon

appConfig.ui.icons.loading

string

The icon when the loading prop is true.

type

'button'

"reset" | "submit" | "button"

The type of the button when not a link.

disabled

boolean

ui

PartialString<{ base: string[]; label: string; leadingIcon: string; leadingAvatar: string; trailingIcon: string; }>

The Button component extends the Link component. Check out the source code on GitHub.

Slots

Slot Type
leading

{}

default

{}

trailing

{}

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        base: [
          'rounded-md 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',
        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: '',
          error: '',
          red: '',
          orange: '',
          amber: '',
          yellow: '',
          lime: '',
          green: '',
          emerald: '',
          teal: '',
          cyan: '',
          sky: '',
          blue: '',
          indigo: '',
          violet: '',
          purple: '',
          fuchsia: '',
          pink: '',
          rose: '',
          gray: ''
        },
        variant: {
          solid: '',
          outline: '',
          soft: '',
          subtle: '',
          ghost: '',
          link: ''
        },
        size: {
          xs: {
            base: 'px-2 py-1 text-xs gap-1',
            leadingIcon: 'size-4',
            trailingIcon: 'size-4'
          },
          sm: {
            base: 'px-2.5 py-1.5 text-xs gap-1.5',
            leadingIcon: 'size-4',
            trailingIcon: 'size-4'
          },
          md: {
            base: 'px-2.5 py-1.5 text-sm gap-1.5',
            leadingIcon: 'size-5',
            trailingIcon: 'size-5'
          },
          lg: {
            base: 'px-3 py-2 text-sm gap-2',
            leadingIcon: 'size-5',
            trailingIcon: 'size-5'
          },
          xl: {
            base: 'px-3 py-2 text-base gap-2',
            leadingIcon: 'size-6',
            trailingIcon: 'size-6'
          }
        },
        block: {
          true: {
            base: 'w-full',
            trailingIcon: 'ms-auto'
          }
        },
        square: {
          true: ''
        },
        leading: {
          true: ''
        },
        trailing: {
          true: ''
        },
        loading: {
          true: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: 'solid',
          class: 'text-white dark:text-gray-900 bg-primary-500 hover:bg-primary-600 disabled:bg-primary-500 aria-disabled:bg-primary-500 dark:bg-primary-400 dark:hover:bg-primary-500 dark:disabled:bg-primary-400 dark:aria-disabled:bg-primary-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 dark:focus-visible:outline-primary-400'
        },
        {
          color: 'primary',
          variant: 'outline',
          class: 'ring ring-inset ring-primary-500/50 dark:ring-primary-400/50 text-primary-500 dark:text-primary-400 hover:bg-primary-500/10 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-primary-400/10 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400'
        },
        {
          color: 'primary',
          variant: 'soft',
          class: 'text-primary-500 dark:text-primary-400 bg-primary-500/10 hover:bg-primary-500/15 focus-visible:bg-primary-500/15 disabled:bg-primary-500/10 aria-disabled:bg-primary-500/10 dark:bg-primary-400/10 dark:hover:bg-primary-400/15 dark:focus-visible:bg-primary-400/15 dark:disabled:bg-primary-400/10 dark:aria-disabled:bg-primary-400/10'
        },
        {
          color: 'primary',
          variant: 'subtle',
          class: 'text-primary-500 dark:text-primary-400 ring ring-inset ring-primary-500/25 dark:ring-primary-400/25 bg-primary-500/10 hover:bg-primary-500/15 disabled:bg-primary-500/10 aria-disabled:bg-primary-500/10 dark:bg-primary-400/10 dark:hover:bg-primary-400/15 dark:disabled:bg-primary-400/10 dark:aria-disabled:bg-primary-400/10 focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400'
        },
        {
          color: 'primary',
          variant: 'ghost',
          class: 'text-primary-500 dark:text-primary-400 hover:bg-primary-500/10 focus-visible:bg-primary-500/10 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-primary-400/10 dark:focus-visible:bg-primary-400/10 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent'
        },
        {
          color: 'primary',
          variant: 'link',
          class: 'text-primary-500 hover:text-primary-600 disabled:text-primary-500 aria-disabled:text-primary-500 dark:text-primary-400 dark:hover:text-primary-500 dark:disabled:text-primary-400 dark:aria-disabled:text-primary-400 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400'
        },
        {
          color: 'gray',
          variant: 'solid',
          class: 'text-white dark:text-gray-900 bg-gray-900 hover:bg-gray-700 disabled:bg-gray-900 aria-disabled:bg-gray-900 dark:bg-white dark:hover:bg-gray-200 dark:disabled:bg-white dark:aria-disabled:bg-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 dark:focus-visible:outline-white'
        },
        {
          color: 'gray',
          variant: 'outline',
          class: 'ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-white hover:bg-gray-100 disabled:bg-white aria-disabled:bg-white dark:bg-gray-900 dark:hover:bg-gray-800 dark:disabled:bg-gray-900 dark:aria-disabled:bg-gray-900 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white'
        },
        {
          color: 'gray',
          variant: 'soft',
          class: 'text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 focus-visible:bg-gray-200 disabled:bg-gray-100 aria-disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:focus-visible:bg-gray-700/50 dark:disabled:bg-gray-800 dark:aria-disabled:bg-gray-800'
        },
        {
          color: 'gray',
          variant: 'subtle',
          class: 'ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 disabled:bg-gray-100 aria-disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:disabled:bg-gray-800 dark:aria-disabled:bg-gray-800 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white'
        },
        {
          color: 'gray',
          variant: 'ghost',
          class: 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 focus-visible:bg-gray-100 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-gray-800 dark:focus-visible:bg-gray-800 dark:hover:disabled:bg-transparent dark:hover:aria-disabled:bg-transparent'
        },
        {
          color: 'gray',
          variant: 'link',
          class: 'text-gray-500 hover:text-gray-700 disabled:text-gray-500 aria-disabled:text-gray-500 dark:text-gray-400 dark:hover:text-gray-200 dark:disabled:text-gray-400 dark:aria-disabled:text-gray-400 focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white'
        },
        {
          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'
      }
    }
  }
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.