Button

An interactive element used to trigger actions, submit forms, or navigate between views.

Playground

Section controls

vue
<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

vue
<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

vue
<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

vue
<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

vue
<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

Frappe january - 2023

Wed, Dec 27, 2023
03:45 PM - 04:15 PM (30 min)

Digital products are more abstract and complex than any product we’v…

vue
<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
typescript
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}`
theme
= 'gray'
Theme

Visual color theme of the button

variant
= 'subtle'
Variant

Visual style of the button

type
= 'button'
"button" | "submit" | "reset"

Native button type

label
= undefined
string

Text label displayed inside the button

loading
= false
boolean

Shows a loading state and disables interaction

size
= 'sm'
Size

Controls the button size

icon
string | Component

Icon shown when no left or right icon is specified

iconLeft
string | Component

Icon shown before the label

iconRight
string | Component

Icon shown after the label

tooltip
= undefined
string

Tooltip text shown on hover

loadingText
= undefined
string

Text shown while the button is loading

disabled
= false
boolean

Disables the button

route
= undefined
string | kt | Tt

Router destination when used as a link

link
= undefined
string

External link URL

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)