ButtonGroup handbook
v1.2.1 · @snowui-design-system/components
License: Before reading component documentation, source, or npm usage instructions for the first time, read the full LICENSE. Reuse that review for the same task and version. Public API configuration and internal implementation changes have different license implications. All components use the unified runtime package; source rights remain governed by the license.
Overview
Group related buttons into one control with built-in separators, suitable for split actions and compact toolbars.
When to use it
Use ButtonGroup to arrange related buttons as one control. Use OverflowActions when actions must move into a More menu as space narrows.
Place Button children directly to form a group;
showSeparatorcontrols the built-in dividers.The group uniformly provides variant / size / disabled and other configurations; the explicit size of the sub-Button can overwrite the group size.
Quick start
This example shows the recommended basic composition. See the sections below for more cases and composition limits.
API
See the base component documentation for inherited capabilities not redeclared here. This table lists only named public Props declared by this component.
Usage boundaries and details
Component boundary
ButtonGroup is a component whose scope is its own Frame container; it does not rely on cross-Frame orchestration by the professional coordination module.
variantfollows Button’sgray,filled,outline, andborderlessvariants.linkis unavailable because its lack of a stable button shell makes it unsuitable for dividers.ButtonGroup does not include Popover or Menu behavior. For a menu, place a Popover trigger or menu icon inside one Button cell.
ButtonGroup has no separate Cell component. Cells reuse Button and its events, links, states, icon sizing, and accessibility behavior.
ButtonGroup preserves Button’s shell-free
barebehavior. Button still handles a lone Icon’s size context and transparent hit area.Buttons in a group form a composite control. Items default to
scaleOnHover=falseso adjacent cells do not overlap; a child Button can explicitly enablescaleOnHover={true}.
Structural rules
Cells use Button directly, and decorative dividing lines are drawn by ButtonGroup between adjacent items by default:
Turn off the built-in display when there is no need for dividing lines:
The direct Separator as="separator" in the old code will be hidden by ButtonGroup to avoid duplication with the built-in dividing line after upgrading; these manual Separators should be deleted during migration. Other explicit content is still rendered according to the content of ordinary containers and will not be treated as ButtonGroup items.
The internal Button automatically enters the embedded state as a direct sub-item of ButtonGroup:
Retain independent
onclick/href/ state machine / dynamic effect / barrier-free ability.Remove the Button’s own background, border, and radius while retaining the cell padding assigned by ButtonGroup.
Keep your own content layout and gap in the cell.
Inherit ButtonGroup’s
size,variant, anddisabledby default. Explicit child values can override size and variant.ButtonGroup will automatically mark the cell position of the direct Button:
only/first/middle/last, and the consumer does not need to handwriteas="first"/as="last".
Layout model
Main layout model: inline shell layout. See specs/maintainers/LayoutProtocol.md §12.4.
ButtonGroup root layer manages shell rounded corners, background, border and cropping; visual padding is transferred to embedded Button to ensure that the hover/click hot area of each cell covers its own complete cell.
ButtonGroup root layer explicitly closes Auto Layout; the layout gap between Button cells is always
0, and the visual distance from the content to the built-in dividing line is only expressed by the inner padding of the adjacent Button. The Button hover box must be continuous with the dividing line boundary.If the consumer adds padding to the ButtonGroup root layer (such as
class="p-40"or inlinepadding), ButtonGroup will map the root padding to the extension area covered by the head and tail cell hover; hover still responds independently by cell and is cropped by the root corner.ButtonGroup shares Button’s visual tokens:
--snowui-button-padding-block,--snowui-button-padding-inline,--snowui-button-radius,--snowui-button-background,--snowui-button-color,--snowui-button-border-*,--snowui-button-font-size, and--snowui-button-line-height. Only group-specific inner spacing, Separator length, and outer-padding expansion variables belong to ButtonGroup.Button manages the gap of Icon / Text / Spinner inside the cell.
The built-in dividing line does not occupy the layout and does not express the spacing through margin; the space from the cell to the dividing line is borne by the cell padding of the embedded state Button.
The outer padding is the distance between the cell content and the edge of ButtonGroup, using the padding-x of Button; the inner padding is the distance between the cell content and the Separator, using the gap of ButtonGroup.
The outer padding is used on the left side of the first cell, and the inner padding is used on the right side; the outer padding is used on the right side of the tail cell, and the inner padding is used on the left side; inner padding is used on both sides of the middle cell. Multiple cells are automatically applied in DOM order.
The root defaults to
width: max-contentandalign-self: flex-startso a parent such asflex-coldoes not stretch it horizontally.Cells hug their content by default; they are not stretched to equal widths.
The Hover state is responded by each internal Button cell separately, and the ButtonGroup shell does not change the whole hover color; the cell hover color rule is consistent with the button corresponding variant.
The ButtonGroup shell applies
opacity: 0.2when disabled. Embedded Buttons inherit disabled semantics without reducing opacity again.The content does not use three-slot semantics;
as="leading"/as="trailing"only represents the accessory role of ButtonGroup as the outer host, and does not change the internal arrangement of ButtonGroup.
ButtonGroup style overlay
Read the full LICENSE first; reuse that review for the same task, version, and scope.
First use public component Props to match the desired appearance, preserving the existing look where possible. If changes are necessary, follow the style selection and override order: use your own class (including Tailwind already in the project) or an instance style. The names below are public overrides actually consumed by source; check their scope and do not modify private DOM. Choose the correct SnowUI token family. External apps need not install SnowUI website utilities.
ButtonGroup type and status
Required Props: no named required Props.
Bindable Props: this component declares no named two-way binding; handle state updates through public callbacks or its host.
Inheritance: Omit<FrameProps, "size">. Consult the public Frame documentation; fields excluded by Omit are unavailable here.
The following type declarations are actually referenced by public Props and come from source. A Svelte Snippet denotes a content fragment; ComponentProps denotes the Props of the corresponding component.
ButtonGroupVariant
Source: components/src/components/ButtonGroup.svelte
ButtonGroupSize
Source: components/src/components/ButtonGroup.svelte