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. |
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. | |
disabled |
| |
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'
}
}
}
})