shadcn-html / button-group
Built with: CSS
Button Group
Groups related buttons with connected borders. Built on a <div> container
that merges adjacent button edges. CSS only — no JavaScript.
Horizontal
Default horizontal group with connected outline buttons.
<div class="btn-group" role="group" aria-label="Actions">
<button class="btn" data-variant="outline">Save</button>
<button class="btn" data-variant="outline">Edit</button>
<button class="btn" data-variant="outline">Delete</button>
</div>
With icons
Icon-only button group for compact toolbars.
<div class="btn-group" role="group" aria-label="Formatting">
<button class="btn" data-variant="outline" data-size="icon" aria-label="Bold">...</button>
<button class="btn" data-variant="outline" data-size="icon" aria-label="Italic">...</button>
<button class="btn" data-variant="outline" data-size="icon" aria-label="Underline">...</button>
</div>
Vertical
Stacked buttons with connected top/bottom borders.
<div class="btn-group" data-orientation="vertical" role="group" aria-label="Nav">
<button class="btn" data-variant="outline">Top</button>
<button class="btn" data-variant="outline">Middle</button>
<button class="btn" data-variant="outline">Bottom</button>
</div>
Separator
Use <hr role="separator"> to visually divide non-outline buttons. Outline buttons don't need separators since they have visible borders.
<div class="btn-group" role="group" aria-label="Clipboard">
<button class="btn" data-variant="default">Copy</button>
<hr role="separator">
<button class="btn" data-variant="default">Paste</button>
</div>
Sizes
Control button size with data-size on individual buttons.
<!-- Small -->
<div class="btn-group" role="group" aria-label="Actions">
<button class="btn" data-variant="outline" data-size="sm">Save</button>
<button class="btn" data-variant="outline" data-size="sm">Edit</button>
</div>
<!-- Large -->
<div class="btn-group" role="group" aria-label="Actions">
<button class="btn" data-variant="outline" data-size="lg">Save</button>
<button class="btn" data-variant="outline" data-size="lg">Edit</button>
</div>
Split button
A primary action button with a dropdown trigger.
<div class="btn-group" role="group" aria-label="Split action">
<button class="btn" data-variant="outline">Save</button>
<hr role="separator">
<button class="btn" data-variant="outline" data-size="icon"
aria-label="More options">
<i data-lucide="chevron-down"></i>
</button>
</div>
CSS view file
/* -- Button Group component ------------------------------------- */
@layer components {
.btn-group {
display: inline-flex;
align-items: stretch;
/* Collapse borders between adjacent buttons */
& > .btn + .btn {
margin-inline-start: -1px;
}
/* Remove internal radii for connected appearance */
& > .btn:not(:first-child):not(:has(+ [role="separator"])) {
border-start-start-radius: 0;
border-end-start-radius: 0;
}
& > .btn:not(:last-child):not([role="separator"] + .btn) {
border-start-end-radius: 0;
border-end-end-radius: 0;
}
/* Buttons after a separator get start radii back */
& > [role="separator"] + .btn {
border-start-start-radius: var(--radius-md);
border-end-start-radius: var(--radius-md);
}
/* Buttons before a separator get end radii back */
& > .btn:has(+ [role="separator"]) {
border-start-end-radius: var(--radius-md);
border-end-end-radius: var(--radius-md);
}
/* Ensure hovered/focused button stacks above its neighbors */
& > .btn:hover,
& > .btn:focus-visible {
position: relative;
z-index: 1;
}
/* -- Separator ------------------------------------------- */
& > [role="separator"] {
width: 1px;
align-self: stretch;
background: var(--border);
border: 0;
margin: 0;
padding: 0;
flex-shrink: 0;
}
/* -- Vertical orientation -------------------------------- */
&[data-orientation="vertical"] {
flex-direction: column;
align-items: stretch;
& > .btn + .btn {
margin-inline-start: 0;
margin-top: -1px;
}
& > .btn:not(:first-child) {
border-start-start-radius: 0;
border-start-end-radius: 0;
border-end-start-radius: var(--radius-md);
}
& > .btn:not(:last-child) {
border-end-start-radius: 0;
border-end-end-radius: 0;
border-start-end-radius: var(--radius-md);
}
& > .btn:first-child {
border-start-start-radius: var(--radius-md);
border-start-end-radius: var(--radius-md);
}
& > .btn:last-child {
border-end-start-radius: var(--radius-md);
border-end-end-radius: var(--radius-md);
}
& > [role="separator"] {
width: auto;
height: 1px;
}
}
}
@media (forced-colors: active) {
.btn-group > [role="separator"] {
background: ButtonText;
}
}
}