Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Primitives
  • Accordion
  • Alert
  • Alert dialog
  • Aspect ratio
  • Autocomplete
  • Avatar
  • Badge
  • Button
  • Button group
  • Calendar
  • Card
  • Checkbox
  • Checkbox Group
  • Code
  • Code Diff
  • Collapsible
  • Color Picker
  • Combobox
  • Command
  • Date Picker
  • Dialog
  • Drawer
  • Empty
  • Field
  • Form
  • Gradient Editor
  • Hover card
  • Input
  • Input group
  • Input OTP
  • Item
  • Kbd
  • Markdown
  • Menu
  • Menubar
  • Meter
  • Native select
  • Navigation menu
  • Number Field
  • Pagination
  • Popover
  • Progress
  • Radio group
  • Resizable
  • Scroll area
  • Select
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Table of contents
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toolbar
  • Tooltip
  • Tree
  • Trigger Menu
  • Typography
Hooks
  • Use Chat Message
  • Use Chat Input
  • Use User Ask
  • Use Audio Recorder
  • Use Environment Variables
  • Use Copy To Clipboard
  • Use Tool Call
  • Use Sidebar Resize
Utils
  • cn
  • Skin
  • Contracts
  • Serialize
Extensions
  • Control Effects
  • View Transition
  • Send Aurora
  1. Primitives
  2. Button group
Primitives

Button group

Joined button group for toolbars, split actions, and segmented controls.

Composition

The preferred shape for composing the installed primitive from its exported parts.

Parts

Exported compound parts from the installed source.

ButtonGroup
├── ButtonGroupText
└── ButtonGroupSeparator

The refined source installs this primitive from src/registry/sources/refined/ui/button-group.tsx. Install it on its own with the command above, or inspect the source below.

Registry command
npx shadcn@latest add http://127.0.0.1:3000/r/refined/button-group.json
See registry manifest

Raw code

Primary installed primitive source

Button group slot
src/registry/sources/refined/ui/button-group.tsx
import { cva } from "class-variance-authority";
import type { ComponentProps } from "react";
import type { ButtonGroupProps, ButtonGroupSeparatorProps, ControlSize } from "@/components/refined-ui/contracts";
import { controlSize } from "@/components/refined-ui/control-variants";
import { cn } from "@/components/refined-ui/lib/cn";
import { skinSlot } from "@/components/refined-ui/skin";
​
// Plain-markup wrapper (no Base UI): collapses inner corners + overlaps borders (-ml-px/-mt-px) into one segmented control; focus-within:z-10 lifts ring above the overlap.
const buttonGroupVariant = cva("inline-flex w-fit items-stretch [&>*]:relative [&>*]:focus-within:z-10", {
variants: {
orientation: {
horizontal: "flex-row [&>*:not(:first-child)]:-ml-px [&>*:not(:first-child)]:rounded-l-none [&>*:not(:last-child)]:rounded-r-none",
vertical: "flex-col [&>*:not(:first-child)]:-mt-px [&>*:not(:first-child)]:rounded-t-none [&>*:not(:last-child)]:rounded-b-none",
},
},
defaultVariants: {
orientation: "horizontal",
},
});
​
export function ButtonGroup({ orientation = "horizontal", className, ...props }: ButtonGroupProps) {
return (
// biome-ignore lint/a11y/useSemanticElements: a segmented control is a labelled group, not a fieldset form group.
<div
role="group"
data-ui="agent"
data-slot="button-group"
data-orientation={orientation}
className={cn(buttonGroupVariant({ orientation }), skinSlot("button-group", { orientation }), className)}
{...props}
/>
);
}
​
// Non-interactive addon label styled to fuse with the group, e.g. a `https://` prefix or unit suffix.
type ButtonGroupTextProps = ComponentProps<"div"> & {
size?: ControlSize;
};
​
export function ButtonGroupText({ size = "sm", className, ...props }: ButtonGroupTextProps) {
return (
<div
data-ui="agent"
data-slot="button-group-text"
data-size={size}
className={cn(
"inline-flex items-center whitespace-nowrap rounded-[var(--radius-control)] border bg-card/72 font-medium text-muted-foreground shadow-sm [&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0",
controlSize({ size }),
skinSlot("button-group-text", {}),
className,
)}
{...props}
/>
);
}
​
export function ButtonGroupSeparator({ orientation = "vertical", className, ...props }: ButtonGroupSeparatorProps) {
return (
<div
aria-hidden="true"
data-ui="agent"
data-slot="button-group-separator"
data-orientation={orientation}
className={cn("shrink-0 self-stretch bg-border", orientation === "vertical" ? "w-px" : "h-px w-full", className)}
{...props}
/>
);
}
​

On this page

  • Preview
  • Composition
  • Installation
  • Source
https://