[Feature Request] Add `VSplitButton` Component
Author: avinash-skylarkdronesCreated Sep 17, 2025Updated Sep 11, 2026
LabelsT: featureC: New Component
Problem to solve
Description
Currently, Vuetify does not provide a built-in SplitButton component. A SplitButton combines:
- A primary action button (executes the most common/primary action).
- A secondary dropdown toggle (reveals additional related actions).
This pattern is widely used in enterprise apps, admin panels, and productivity tools to reduce button clutter while still offering quick access to multiple related commands.
Proposed API / Usage Example
<v-split-btn
label="Save"
:items="[
{ label: 'Save As Draft', value: 'draft' },
{ label: 'Save & Publish', value: 'publish' }
]"
color="primary"
variant="flat"
size="large"
@click="onSave"
@click:item="onSplitAction"
/>Props:
label→ primary action textitems→ array of dropdown items (or allow slot for full flexibility)color,variant,size→ inherited fromv-btnfor consistency
Events:
primary-click→ when the main button is clickeditem-click→ when a dropdown item is selected
Why this belongs in Vuetify
- Material Design Adjacent: Many modern design systems (Material Design, Fluent UI, Bootstrap, Ant Design) include split buttons because they solve a common UX problem: offering a default action with secondary options nearby.
- Developer Experience: Today, developers must manually compose
v-btn+v-menu+v-list. This is repetitive boilerplate and inconsistent across projects. - Consistency: A canonical Vuetify implementation would ensure accessibility (keyboard navigation, focus trapping, aria roles), consistent sizing/alignment, and theme support.
Alternatives Today
- Manually compose a
v-btnand av-menuwithv-list(works, but verbose and error-prone). - Use
v-btn-toggle(not semantically the same, doesn’t support a primary action + dropdown).
References
- Material Design: Split Button
- Fluent UI:
SplitButton - Bootstrap: Split Button Dropdowns
- Ant Design: Dropdown Button
Additional Context
This component would be especially valuable in enterprise dashboards, admin panels, and data-heavy applications, where contextual actions need to be accessible but not overwhelming.
Proposed solution
<template>
<div class="d-inline-flex">
<!-- Primary Action Button -->
<v-btn
:color="props.color"
:variant="props.variant"
:size="props.size"
@click="emit('click')"
>
<slot>{{ props.label }}</slot>
</v-btn>
<!-- Dropdown Menu -->
<v-menu>
<template #activator="{ props: menuProps }">
<v-btn
v-bind="menuProps"
:color="props.color"
:variant="props.variant"
:size="props.size"
icon
>
<!-- Or let this icon be a prop/slot -->
<v-icon>mdi-chevron-down</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in props.items"
:key="index"
@click="emit('click:item', item)"
>
<v-list-item-title>{{ item.label }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</template>
<script setup lang="ts">
// Or use a similar existing type
type SplitButtonItem = {
label: string;
value?: string | number | boolean | object;
};
// Or use a similar existing type
type SplitButtonVariant =
| "text"
| "flat"
| "outlined"
| "tonal"
| "elevated"
| "plain";
// Or use a similar existing type
type SplitButtonSize =
| "x-small"
| "small"
| "default"
| "large"
| "x-large";
// Or use a similar existing type
type SplitButtonProps = {
label?: string;
items?: SplitButtonItem[];
color?: string;
variant?: SplitButtonVariant;
size?: SplitButtonSize;
};
// Or use a similar existing type
type SplitButtonEmits = {
(e: "click"): void;
(e: "click:item", item: SplitButtonItem): void;
};
const props = withDefaults(defineProps<SplitButtonProps>(), {
label: "Action",
items: () => [],
color: "primary",
variant: "flat",
size: "default",
});
const emit = defineEmits<SplitButtonEmits>();
</script>Source: vuetifyjs/vuetify