# Split Button

A button that offers a primary interaction coupled with a dropdown menu offering additional actions.

---

## Default

The button's primary action should be the first item in the dropdown menu.

```tsx
import type { ButtonProps } from '@vercel/geistcn/components';
import { SplitButton, SplitButtonMenuItem } from '@vercel/geistcn/components';
import type { JSX } from 'react';

const SIZES: ButtonProps['size'][] = ['small', 'medium', 'large'];
const TYPES: Extract<ButtonProps['variant'], 'default' | 'secondary'>[] = [
  'default',
  'secondary',
];

export function Component(): JSX.Element {
  return (
    <div className="flex flex-col items-start justify-between gap-8 flex-initial">
      {TYPES.map((variant) => {
        return (
          <div
            key={variant}
            className="flex flex-row items-stretch justify-start gap-4 flex-initial"
          >
            {SIZES.map((size) => {
              return (
                <SplitButton
                  buttonProps={{
                    onClick: () => {
                      alert('Clicked Saved');
                    },
                    size,
                    variant,
                  }}
                  key={`${variant}`}
                  menuButtonLabel="Select save method"
                  menuItems={
                    <>
                      <SplitButtonMenuItem
                        description="Save changes"
                        menuItemProps={{
                          onClick: () => {
                            alert('Clicked Save');
                          },
                        }}
                        title="Save"
                      />
                      <SplitButtonMenuItem
                        description="Save changes and create a new production deployment"
                        menuItemProps={{
                          onClick: () => {
                            alert('Clicked Save + Redeploy');
                          },
                        }}
                        title="Save + Redeploy"
                      />
                    </>
                  }
                  menuProps={{ width: 264 }}
                >
                  Save
                </SplitButton>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}
```

## Menu Alignment

```tsx
import { SplitButton, SplitButtonMenuItem } from '@vercel/geistcn/components';
import type { JSX } from 'react';

export function Component(): JSX.Element {
  return (
    <div className="flex flex-row items-start justify-start gap-8 flex-initial">
      <SplitButton
        buttonProps={{
          onClick: () => {
            alert('Clicked Saved');
          },
        }}
        menuButtonLabel="Select save method"
        menuItems={
          <>
            <SplitButtonMenuItem
              description="Save changes"
              menuItemProps={{
                onClick: () => {
                  alert('Clicked Save');
                },
              }}
              title="Save"
            />
            <SplitButtonMenuItem
              description="Save changes and create a new production deployment"
              menuItemProps={{
                onClick: () => {
                  alert('Clicked Save + Redeploy');
                },
              }}
              title="Save + Redeploy"
            />
          </>
        }
        menuProps={{ width: 264 }}
      >
        Save
      </SplitButton>

      <SplitButton
        buttonProps={{
          onClick: () => {
            alert('Clicked Saved');
          },
        }}
        menuAlignment="bottom-end"
        menuButtonLabel="Select save method"
        menuItems={
          <>
            <SplitButtonMenuItem
              description="Save changes"
              menuItemProps={{
                onClick: () => {
                  alert('Clicked Save');
                },
              }}
              title="Save"
            />
            <SplitButtonMenuItem
              description="Save changes and create a new production deployment"
              menuItemProps={{
                onClick: () => {
                  alert('Clicked Save + Redeploy');
                },
              }}
              title="Save + Redeploy"
            />
          </>
        }
        menuProps={{ width: 264 }}
      >
        Save
      </SplitButton>
    </div>
  );
}
```

## Icon

```tsx
import { SplitButton, SplitButtonMenuItem } from '@vercel/geistcn/components';
import { LogoOpenAi, LogoV0 } from '@vercel/geistcn/icons';
import type { JSX } from 'react';

export function Component(): JSX.Element {
  return (
    <SplitButton
      buttonProps={{
        onClick: () => {
          console.log('Copy page');
        },
        size: 'small',
        variant: 'secondary',
      }}
      menuButtonLabel="Copy page"
      menuItems={[
        <SplitButtonMenuItem
          key="v0"
          description="Open this page in v0"
          menuItemProps={{
            onClick: () => {
              console.log('v0');
            },
            className: 'w-[200px]',
          }}
          title="Open in v0"
          icon={<LogoV0 className="w-4 h-4" />}
        />,
        <SplitButtonMenuItem
          key="chatgpt"
          description="Open this page in ChatGPT"
          menuItemProps={{
            onClick: () => {
              console.log('ChatGPT');
            },
            className: 'w-[200px]',
          }}
          title="Open in ChatGPT"
          icon={<LogoOpenAi className="w-4 h-4" />}
        />,
      ]}
      menuProps={{ width: 240 }}
    >
      Copy page
    </SplitButton>
  );
}
```

## Title with Icon

```tsx
import type { ButtonProps } from '@vercel/geistcn/components';
import { SplitButton, SplitButtonMenuItem } from '@vercel/geistcn/components';
import {
  IconArrowCircleUp,
  IconFloppyDisk,
} from '@vercel/geistcn-assets/icons';
import type { JSX } from 'react';

const SIZES: ButtonProps['size'][] = ['small', 'medium', 'large'];
const VARIANTS: Extract<ButtonProps['variant'], 'default' | 'secondary'>[] = [
  'default',
  'secondary',
];

export function Component(): JSX.Element {
  return (
    <div className="flex flex-col justify-between gap-8">
      {VARIANTS.map((variant) => {
        return (
          <div className="flex flex-row gap-1" key={variant}>
            {SIZES.map((size) => {
              return (
                <SplitButton
                  buttonProps={{
                    onClick: () => {
                      alert('Clicked Saved');
                    },
                    size,
                    variant,
                  }}
                  key={`${variant}`}
                  menuButtonLabel="Select save method"
                  menuItems={
                    <>
                      <SplitButtonMenuItem
                        description="Save changes"
                        menuItemProps={{
                          onClick: () => {
                            alert('Clicked Save');
                          },
                        }}
                        title={
                          <span className="flex gap-2 items-center">
                            <IconFloppyDisk /> Save
                          </span>
                        }
                      />
                      <SplitButtonMenuItem
                        description="Save changes and create a new production deployment"
                        menuItemProps={{
                          onClick: () => {
                            alert('Clicked Save + Redeploy');
                          },
                        }}
                        title={
                          <span className="flex gap-2 items-center">
                            <IconArrowCircleUp /> Save + Redeploy
                          </span>
                        }
                      />
                    </>
                  }
                  menuProps={{ width: 264 }}
                >
                  Save
                </SplitButton>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}
```

## Best Practices

* Use a Split Button when one action is the clear default and 1–4 close variants belong next to it, like `Deploy` paired with `Deploy to Preview`. For unrelated actions, use a `Menu` instead.
* Mirror the primary action as the first item in the dropdown so keyboard users and screen readers get the same options. The visible button label and the first item must match exactly.
* Restrict the primary `type` to `default` or `secondary`. The API blocks the destructive variants on purpose, since hiding a delete inside a dropdown is a sharp edge.
* Title Case every menu item label and follow `Verb + Noun`: `Deploy to Production`, `Promote to Production`, `Rollback Deployment`. Group destructive items at the bottom with a divider.
* Set `menuButtonLabel` to a screen-reader sentence that names the action set, like `More deploy options`. It becomes the `aria-label` on the dropdown trigger and is the only label a screen reader hears for that button.
* Default `menuAlignment="bottom-start"` aligns the menu under the primary button; switch to `bottom-end` only when the button sits flush with the right edge of its container.
