Kebab
A compact icon-only "more actions" trigger. Pair it with a menu; the orientation prop toggles the vertical (⋮) or horizontal (⋯) overflow glyph.
Installation
$
Usage
import { Kebab } from "@/components/ui/kebab"Examples
Default
The vertical (⋮) kebab, wired to a DropdownMenu via render. This is the conventional row and list "more actions" affordance.
Orientation
Pass orientation="horizontal" for the ⋯ meatball, better suited to dense horizontal toolbars.
vertical (default)
horizontal
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| orientation | "vertical" | "horizontal" | "vertical" | Dot axis of the overflow glyph: vertical renders ⋮, horizontal renders ⋯. |
| variant | "default" | "soft" | "outline" | "ghost" | "text" | "destructive" | "subtle" | "ghost-destructive" | "link" | "ghost" | Button variant. Defaults to ghost so the trigger stays quiet until hovered. |
| size | "default" | "xs" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | "inline" | "icon" | Button size preset. Defaults to icon (32px square) to match the default button height. |
| iconSize | "xs" | "sm" | "default" | "lg" | "xl" | "lg" | Size of the overflow glyph. Defaults to lg (20px) so the dots fill the button; drop to sm for a subtler affordance. |
| ...props | ButtonProps | - | Every other Button prop (aria-label, disabled, onClick, asChild, className, ...) is forwarded. aria-label defaults to "More actions". |
"use client"
import { MoreHorizontal, MoreVertical } from "lucide-react"
import { cn } from "@/registry/lib/utils"
import { Button, type ButtonProps } from "@/registry/ui/button"
type KebabProps = Omit<ButtonProps, "iconStart" | "iconEnd" | "children"> & {
/**
* Dot axis of the overflow glyph:
* - "vertical" → ⋮ (default; the conventional row/list "more actions" affordance)
* - "horizontal" → ⋯ (better in dense horizontal toolbars)
*/
orientation?: "vertical" | "horizontal"
}
/**
* The canonical "more actions" trigger: an icon-only button rendering an
* overflow glyph. Pair it with a menu via the `render` prop, e.g.
* `<DropdownMenuTrigger render={<Kebab />} />`.
*
* Defaults to the vertical (⋮) kebab; pass `orientation="horizontal"` for the
* ⋯ meatball. The default 28px square matches `Button size="sm"`; it grows to
* a 44px target on coarse pointers. Its 14px glyph is optically balanced in
* the compact hover target. Everything else is a normal `Button` (variant,
* size, iconSize, disabled, aria-label, …) so it inherits the design system's
* states for free.
*/
function Kebab({
orientation = "vertical",
variant = "ghost",
size,
iconSize,
className,
...props
}: KebabProps) {
return (
<Button
aria-label="More actions"
variant={variant}
size={size ?? "icon"}
iconSize={iconSize ?? "sm"}
// The radius travels WITH the 28px override: `size="icon"` ships a 32px
// box and the 12px corner that matches it, and 12px on 28px reads as a
// pill. `rounded-action-sm` is the 28px rung. Drop the height, drop the
// radius with it.
className={cn(
size === undefined && "size-7 rounded-action-sm pointer-coarse:size-11",
className
)}
iconStart={orientation === "vertical" ? MoreVertical : MoreHorizontal}
{...props}
/>
)
}
export { Kebab }
export type { KebabProps }