Skip to main content
Clever Ops

Split Button

A self-contained split button for React, filled primary action, hairline-divided menu toggle, and real role=menu keyboard semantics with zero Radix or portal dependencies.

Preview & code

Loading Split Button preview

Installation

pnpm dlx shadcn@latest add @cleverui/button-split

Requires the @cleverui registry in your components.json, a one-off, two-line setup.

Usage

tsx
import { ButtonSplit } from '@/components/ui/button-split'
Exampletsx
'use client'

import { useState } from 'react'
import { GitMerge, GitBranch, XCircle, Archive } from 'lucide-react'
import { ButtonSplit } from '@/components/ui/button-split'

export default function ButtonSplitDemo() {
  const [status, setStatus] = useState('Ready to merge into main · 3 checks green')

  return (
    <div className="mx-auto flex min-h-[400px] max-w-lg flex-col items-center justify-center gap-12 px-6 py-16">
      <div className="flex w-full flex-col items-center gap-4 text-center">
        <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-muted-foreground">
          Harbor · PR #1842
        </p>
        <p className="max-w-sm text-sm leading-relaxed text-muted-foreground">{status}</p>
        <ButtonSplit
          label="Merge pull request"
          onAction={() => setStatus('Merged into main, deploy pipeline queued')}
          items={[
            {
              label: 'Squash and merge',
              icon: GitMerge,
              onSelect: () => setStatus('Squashed into main as a single commit'),
            },
            {
              label: 'Rebase and merge',
              icon: GitBranch,
              onSelect: () => setStatus('Rebased onto main, linear history kept'),
            },
            {
              label: 'Close without merging',
              icon: XCircle,
              destructive: true,
              onSelect: () => setStatus('Pull request closed without merging'),
            },
          ]}
        />
      </div>

      <div className="flex w-full flex-col items-center gap-4 border-t border-border/60 pt-10 text-center">
        <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-muted-foreground">
          Report · outline register
        </p>
        <ButtonSplit
          label="Export report"
          variant="outline"
          size="sm"
          align="start"
          onAction={() => setStatus('CSV exported, 12,408 rows')}
          items={[
            {
              label: 'Export as PDF',
              icon: Archive,
              onSelect: () => setStatus('PDF package ready for download'),
            },
            {
              label: 'Schedule weekly send',
              onSelect: () => setStatus('Weekly send scheduled every Monday 09:00'),
            },
          ]}
        />
      </div>
    </div>
  )
}

API reference

ButtonSplit accepts the following props.

PropTypeDefaultDescription
label*stringprimary segment label, e.g. 'Merge pull request'
onAction*() => voidfires when the primary segment is activated
items*ButtonSplitItem[]2–5 secondary actions for the menu; destructive items render in text-destructive
variant'primary' | 'outline''primary'primary is the filled register; outline keeps the whole instrument hairline-quiet
size'sm' | 'md''md'h-9 / h-11 heights on the button-shine scale
align'start' | 'end''end'horizontal alignment of the menu against the button
menuLabelstring'More actions'accessible name for the toggle segment and menu

…plus everything from Omit< React.HTMLAttributes<HTMLDivElement>, 'children' | 'onDrag' | 'onDragStart' | 'onDragEnd' | 'onAnimationStart' >: className, event handlers, aria attributes and the rest pass straight through.

Referenced types

Typestsx
export interface ButtonSplitItem {
  label: string
  onSelect: () => void
  icon?: LucideIcon
  destructive?: boolean
}

Frequently asked questions

How do I install the Split Button component?

Register the @cleverui registry in your components.json ("@cleverui": "https://cleverops.com.au/r/{name}.json"), then run `npx shadcn@latest add @cleverui/button-split`. The shadcn CLI copies the source into your project, you own the code from that point. You can also copy the source directly from this page.

What dependencies does Split Button require?

Split Button uses motion and lucide-react on top of React and Tailwind CSS. You don't need to install them manually, the shadcn CLI resolves and installs npm dependencies automatically when you add the component.

Can I theme Split Button to match my brand?

Yes. The component is styled entirely with Tailwind utilities over standard design tokens (primary, background, muted, border), so it inherits your existing shadcn/ui theme automatically. Change your CSS variables and the component follows, no source edits needed for palette, radius, or fonts.

Want this built for you?

CleverUI is built by the Clever Ops web team. If you'd rather ship a hand-coded, fast, custom website than assemble one, we build them for Australian businesses every week.

Explore web development services