Components / Actions

SplitButton

Combines a primary native action with a separate keyboard-accessible menu.

Preview

Install

Run in your project
Package manager
npx @getweini/cli@latest add split-button

Use cases

Primary save plus alternatives

Keep Save as the main action and put format choices in the adjacent menu.

Send with options

Offer a direct send action and alternate scheduling actions.

Usage example

Vue
<script setup lang="ts">
import SplitButton from './components/ui/split-button/SplitButton.vue'

const options = [
  { id: 'draft', label: 'Save as draft' },
  { id: 'template', label: 'Save as template' },
]
function saveAs(item: { id: string }) { console.log(item.id) }
</script>

<template>
  <SplitButton :items="options" menu-label="More save options" @select="saveAs">
    Save
  </SplitButton>
</template>

More examples

Save alternatives

The primary action and menu selection are separate events.

Save alternatives
<script setup lang="ts">
import SplitButton from './components/ui/split-button/SplitButton.vue'
const options = [{ id: 'draft', label: 'Save as draft' }, { id: 'copy', label: 'Save a copy' }]
function save() { /* Save the current document. */ }
function saveAs(id: string) { /* Handle the selected alternative. */ }
</script>
<template><SplitButton :items="options" menu-label="Other save options" @action="save" @select="saveAs($event.id)">Save</SplitButton></template>

Send options

Disable an unavailable alternative without disabling the primary action.

Send options
<script setup lang="ts">
import SplitButton from './components/ui/split-button/SplitButton.vue'
const options = [{ id: 'schedule', label: 'Schedule send' }, { id: 'test', label: 'Send test', disabled: true }]
</script>
<template><SplitButton :items="options" menu-label="Other send options" variant="secondary" @action="$emit('send')" @select="$emit('option', $event.id)">Send now</SplitButton></template>

Key API

The most useful props, models, slots, events, and methods for this component.

Key API for SplitButton
NameTypeDefault or requirement
items{ id; label; disabled?; destructive? }[]required
menuLabelstringrequired
v-model:openbooleanfalse
variantdefault | secondary | outline | destructivedefault
sizesm | md | lgmd
disabled / loadingbooleanfalse
typebutton | submit | resetbutton
width / gapnumber, px224 / 8
align / sidestart | center | end / top | bottomend / bottom

The primary button preserves native form behavior. Menu arrows wrap, Home and End move to the edges, typeahead searches labels, and Escape closes and restores trigger focus.

Implementation notes

  • The menuLabel names the separate menu trigger; the default slot names the primary button.
  • The primary button supports type="submit"; a menu choice never submits the form.

Accessibility and localization

  • Use short, distinct labels for the primary and alternative actions.
  • Escape closes the menu and restores focus to its trigger.
Weini UIDesign system · Vue component library · Free and public