Button
Displays a button for actions in forms, toolbars and navigation.
Installation
npx alixan-ui-nuxt add buttonUsage
Button styling is built from two independent props: variant chooses the visual weight, and color chooses the action intent. Combine them to get the right emphasis without changing the meaning of the action.
Filled
Outlined
Ghost
<script setup lang="ts">
import Button from '@/components/ui/button/Button.vue'
</script>
<template>
<div class="space-y-4">
<div class="flex flex-wrap items-center gap-2">
<Button variant="filled" color="default">Default</Button>
<Button variant="filled" color="primary">Primary</Button>
<Button variant="filled" color="secondary">Secondary</Button>
<Button variant="filled" color="destructive">Destructive</Button>
</div>
<div class="flex flex-wrap items-center gap-2">
<Button variant="outlined" color="default">Default</Button>
<Button variant="outlined" color="primary">Primary</Button>
<Button variant="outlined" color="secondary">Secondary</Button>
<Button variant="outlined" color="destructive">Destructive</Button>
</div>
<div class="flex flex-wrap items-center gap-2">
<Button variant="ghost" color="default">Default</Button>
<Button variant="ghost" color="primary">Primary</Button>
<Button variant="ghost" color="secondary">Secondary</Button>
<Button variant="ghost" color="destructive">Destructive</Button>
</div>
</div>
</template>Size
<script setup lang="ts">
import Button from '@/components/ui/button/Button.vue'
</script>
<template>
<div class="flex items-center gap-2">
<Button size="sm">
Small
</Button>
<Button>
Default
</Button>
<Button size="lg">
Large
</Button>
</div>
</template>With Icon
<script setup lang="ts">
import { ArrowRight, GitBranch } from '@lucide/vue'
import Button from '@/components/ui/button/Button.vue'
</script>
<template>
<div class="flex items-center gap-2">
<Button variant="outlined">
<template #leading>
<GitBranch class="size-5" />
</template>
New Branch
</Button>
<Button variant="outlined">
Continue
<template #trailing>
<ArrowRight class="size-5" />
</template>
</Button>
</div>
</template>Loading
Button does not include a built-in spinner state. If the button keeps spinning inline, the user can still navigate away and lose the action context. A global loader blocks the surface, communicates one active operation, and keeps the experience easier to understand.
<script setup lang="ts">
const loader = useGlobalLoader()
const save = () => {
loader.show({ label: 'componentDocs.button.savingChanges' })
window.setTimeout(() => {
loader.hide()
}, 3000)
}
</script>
<template>
<Button @click="save">Save changes</Button>
</template>Disabled
Prefer not to disable buttons. Keep the action visible and active, then explain why it cannot run with a warning message. This gives the user feedback instead of a dead control.
<script setup lang="ts">
const dialog = useDialog()
const openAlert = () => {
dialog.open(AlertDialog, {
width: '360px',
height: '280px',
data: {
title: 'componentDocs.button.actionUnavailable',
description: 'componentDocs.button.exportUnavailable',
buttonLabel: 'componentDocs.button.gotIt',
},
})
}
</script>
<template>
<Button variant="outlined" @click="openAlert">
Export report
</Button>
</template>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | - | Fallback text when the default slot is not used. |
| variant | 'filled' | 'outlined' | 'ghost' | 'filled' | Surface style. Filled is used by default. Combine it with color for intent. |
| color | 'default' | 'primary' | 'secondary' | 'destructive' | 'default' | Semantic intent. Works with every variant. |
| size | 'sm' | 'md' | 'lg' | 'md' | Controls height, padding and text size. |
| to | RouteLocationRaw | - | Renders the button as a NuxtLink when provided. |
| href | string | - | Renders the button as a native anchor when provided. |
| target | '_blank' | '_self' | '_parent' | '_top' | - | Anchor target. Works with href links. |
| tooltip | string | - | Tooltip content. Values can be translation keys. |