kanpeki
uibutton-groupsource: ok · hit
Button Group
npx shadcn add "https://kanpeki.vercel.app/r/button-group.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightui-primitives@base-ui/react
Registry dependencies
@kanpeki/separator
Files4 · source cached 10/8/2026, 12:51:18 PM
src/registry/ui/button-group/index.ts
export * from "./button-group";
export * as ButtonGroup from "./namespace";
export * from "./styles";
src/registry/ui/button-group/button-group.tsx
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import type { VariantProps } from "cva";
import { Group } from "react-aria-components";
import { Separator } from "~/registry/ui/separator";
import { ButtonGroupStyles } from "./styles";
export interface ButtonGroupRootProps
extends React.ComponentProps<typeof Group>,
VariantProps<typeof ButtonGroupStyles.Root> {}
export function ButtonGroupRoot({
className,
orientation,
...props
}: ButtonGroupRootProps) {
return (
<Group
className={ButtonGroupStyles.Root({ orientation, className })}
data-orientation={orientation}
data-slot="button-group-root"
{...props}
/>
);
}
export interface ButtonGroupTextProps extends useRender.ComponentProps<"div"> {}
export function ButtonGroupText({
render,
className,
...props
}: ButtonGroupTextProps) {
const defaultProps: useRender.ElementProps<"div"> = {
className: ButtonGroupStyles.Text({ className }),
};
return useRender({
defaultTagName: "div",
render,
props: mergeProps<"div">(defaultProps, props),
state: {
slot: "button-group-text",
},
});
}
export interface ButtonGroupSeparatorProps
extends React.ComponentProps<typeof Separator> {}
export function ButtonGroupSeparator({
className,
orientation = "vertical",
...props
}: ButtonGroupSeparatorProps) {
return (
<Separator
className={ButtonGroupStyles.Separator({ className })}
data-slot="button-group-separator"
orientation={orientation}
{...props}
/>
);
}
src/registry/ui/button-group/namespace.ts
export {
ButtonGroupRoot as Root,
ButtonGroupSeparator as Separator,
ButtonGroupText as Text,
} from "./button-group";
src/registry/ui/button-group/styles.ts
import { cva } from "~/registry/lib/cva";
export const ButtonGroupStyles = {
Root: cva({
base: "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group-root]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
variants: {
orientation: {
horizontal:
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
vertical:
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
},
},
defaultVariants: {
orientation: "horizontal",
},
}),
Text: cva({
base: "flex items-center gap-2 rounded-md border bg-muted px-4 font-medium text-sm shadow-xs [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
}),
Separator: cva({
base: "relative m-0! orientation-vertical:h-auto self-stretch bg-input",
}),
};