Button
An interactive element used to trigger actions, submit forms, or navigate between views.
Active state
Button holds the pressed look while its own data-state is open or active — there is no active prop.
Used as a menu trigger, this needs no wiring at all: the menu primitive stamps data-state="open" on the trigger, so the button stays pressed for as long as the menu is open.
<Dropdown :options="options" :button="{ label: 'Options' }" />For a standalone toggle — a toolbar control, a filter chip — set the attribute yourself. It is visual only, so pair it with aria-pressed:
<Button
label="Bold"
:data-state="isBold ? 'active' : 'inactive'"
:aria-pressed="isBold"
/>Playground
<Button
variant="subtle"
theme="gray"
size="sm"
label="Save"
/>Section controls
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div class="flex w-full max-w-[1100px] items-center gap-8">
<div class="flex flex-1 items-center gap-1.5">
<Button>Lead owner</Button>
<Button icon-right="lucide-chevron-down">Status</Button>
<Button icon-right="lucide-chevron-down">Organisation</Button>
</div>
<div class="flex items-center gap-2">
<Button icon-left="lucide-eye-off">Columns</Button>
<Button icon-left="lucide-list-filter">
Filter
<template #suffix>
<span
class="inline-flex h-4.5 items-center justify-center rounded-1 bg-surface-base px-1.5 text-xs text-ink-gray-7 shadow-sm ring-1 ring-black/5"
>
1
</span>
</template>
</Button>
<Button icon-left="lucide-arrow-up-down">Sort</Button>
<Button icon="lucide-ellipsis" />
</div>
</div>
</template>Section action
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div class="flex w-full max-w-[352px] items-center gap-2 p-3">
<Button
variant="ghost"
icon-left="lucide-chevron-down"
class="-ml-2 font-medium"
>
Contacts
</Button>
<div class="flex-1" />
<Button icon-left="lucide-plus">Add contact</Button>
</div>
</template>Selection toolbar
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div
class="inline-flex items-center gap-3.5 rounded-6 bg-surface-base p-1.5 shadow-[0px_0px_1.5px_rgba(0,0,0,0.16),0px_2px_5px_rgba(0,0,0,0.14)]"
>
<Button variant="ghost" icon-left="lucide-x">2 selected</Button>
<div class="h-5 w-px bg-outline-gray-1" />
<div class="flex items-center gap-1">
<Button variant="ghost" icon-left="lucide-download">Download</Button>
<Button variant="ghost" icon-left="lucide-corner-up-right">Move</Button>
<Button variant="ghost" icon-left="lucide-share-2">Share</Button>
<Button variant="ghost" theme="red" icon-left="lucide-trash-2">
Delete
</Button>
</div>
</div>
</template>Inline actions
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div class="flex items-center gap-2">
<Button>Join</Button>
<Button variant="solid">Reschedule</Button>
</div>
</template>Stacked actions
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div class="flex w-58 flex-col items-stretch gap-2">
<Button class="w-full">Join</Button>
<Button variant="solid" class="w-full">Reschedule</Button>
</div>
</template>Card actions
<script setup>
import { Button } from 'frappe-ui'
</script>
<template>
<div
class="flex w-96 flex-col gap-6 rounded-6 bg-surface-base p-4 shadow-[0px_0px_0.75px_rgba(0,0,0,0.16),0px_2px_2.5px_rgba(0,0,0,0.14)]"
>
<div class="flex flex-col gap-5">
<div class="flex flex-col gap-3">
<p class="text-md-semibold text-ink-gray-7">Frappe january - 2023</p>
<div class="flex flex-col gap-3">
<div class="flex items-center gap-2 text-base text-ink-gray-7">
<span class="lucide-calendar size-4" aria-hidden="true" />
<span>Wed, Dec 27, 2023</span>
</div>
<div class="flex items-center gap-2 text-base text-ink-gray-7">
<span class="lucide-clock size-4" aria-hidden="true" />
<span>03:45 PM - 04:15 PM (30 min)</span>
</div>
</div>
</div>
<p class="text-base leading-normal text-ink-gray-7">
Digital products are more abstract and complex than any product we’v…
</p>
</div>
<div class="flex items-center gap-2">
<Button class="flex-1">Start</Button>
<Button variant="solid" class="flex-1" icon-left="lucide-video">
Join
</Button>
</div>
</div>
</template>API Reference
Show types
import { type RouterLinkProps } from 'vue-router'
import { type Component, type ExtractPublicPropTypes, type PropType } from 'vue'
export type Theme = 'gray' | 'blue' | 'green' | 'red'
export type Size = 'xs' | 'sm' | 'md' | 'lg'
export type Variant = 'solid' | 'subtle' | 'outline' | 'ghost'
const iconProp = {
type: [String, Object, Function] as PropType<string | Component>,
default: undefined,
}
/**
* Runtime prop definitions — the single source of truth for the button's props.
* `Button.vue` spreads these into `defineComponent`, and the public `ButtonProps`
* type is derived from them, so the runtime and the type can never drift apart.
*/
export const buttonProps = {
/** Visual color theme of the button */
theme: { type: String as PropType<Theme>, default: 'gray' },
/** Controls the button size */
size: { type: String as PropType<Size>, default: 'sm' },
/** Visual style of the button */
variant: { type: String as PropType<Variant>, default: 'subtle' },
/** Text label displayed inside the button */
label: { type: String, default: undefined },
/** Icon shown when no left or right icon is specified */
icon: iconProp,
/** Icon shown before the label */
iconLeft: iconProp,
/** Icon shown after the label */
iconRight: iconProp,
/** Tooltip text shown on hover */
tooltip: { type: String, default: undefined },
/** Shows a loading state and disables interaction */
loading: { type: Boolean, default: false },
/** Text shown while the button is loading */
loadingText: { type: String, default: undefined },
/** Disables the button */
disabled: { type: Boolean, default: false },
/** Router destination when used as a link */
route: {
type: [String, Object] as PropType<RouterLinkProps['to']>,
default: undefined,
},
/** External link URL */
link: { type: String, default: undefined },
/** Native button type */
type: {
type: String as PropType<'button' | 'submit' | 'reset'>,
default: 'button',
},
}
/** Public prop types for `<Button>`. Derived from {@link buttonProps}. */
export type ButtonProps = ExtractPublicPropTypes<typeof buttonProps>
/** Combined theme and variant key */
export type ThemeVariant = `${Theme}-${Variant}`Visual color theme of the button
Controls the button size
Visual style of the button
Text label displayed inside the button
Icon shown when no left or right icon is specified
Icon shown before the label
Icon shown after the label
Tooltip text shown on hover
Shows a loading state and disables interaction
Text shown while the button is loading
Disables the button
Router destination when used as a link
External link URL
Native button type
| Slot | Payload |
|---|---|
prefix | [void] Content shown before the button label (left icon / custom content) |
icon | [void] Icon-only content for icon buttons |
default | [void] Main button content (overrides `label`) |
suffix | [void] Content shown after the button label (right icon / custom content) |
Content shown before the button label (left icon / custom content)
Icon-only content for icon buttons
Main button content (overrides `label`)
Content shown after the button label (right icon / custom content)