Button Group
Bundle buttons/links as a segmented control. Wrapper auto-zeros border-radius on the center child and collapses shared borders. Hover fills with soft tint on the wrapper, keeping the group visually light (improved v0.3.3). Orientation: horizontal (default) or vertical. No need to add class="join-item" to children (removed v0.3.3).
Minimal (orientation=horizontal is default, no join-item needed)
<x-button-group>
<x-button appearance="outline" color="neutral">Left</x-button>
<x-button appearance="outline" color="neutral">Center</x-button>
<x-button appearance="outline" color="neutral">Right</x-button>
</x-button-group>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0 [&>[aria-pressed=true]:not(:last-child)]:border-r-[length:var(--border)] [&>[aria-pressed=true]+*]:border-l-0 [&>*]:hover:bg-base-200 [&>*]:hover:text-base-content [&>*]:hover:border-base-300">
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Left</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Center</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Right</button>
</div>
orientation=vertical — join vertically
<x-button-group orientation="vertical">
<x-button appearance="outline" color="neutral">Top</x-button>
<x-button appearance="outline" color="neutral">Middle</x-button>
<x-button appearance="outline" color="neutral">Bottom</x-button>
</x-button-group>
<div class="inline-flex flex-col [&>*]:rounded-none [&>*:first-child]:rounded-t-[var(--radius-field)] [&>*:last-child]:rounded-b-[var(--radius-field)] [&>*:not(:last-child)]:border-b-0 [&>[aria-pressed=true]:not(:last-child)]:border-b-[length:var(--border)] [&>[aria-pressed=true]+*]:border-t-0 [&>*]:hover:bg-base-200 [&>*]:hover:text-base-content [&>*]:hover:border-base-300">
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Top</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Middle</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer">Bottom</button>
</div>
with toggle state — build a segmented control with Alpine.js (the active item uses primary fill + !important to sit above the hover override)
Selected:
<div x-data="{ active: 'center' }" class="flex flex-col gap-4">
<x-button-group>
<x-button appearance="outline" color="neutral"
x-bind:class="active === 'left' && '!bg-primary !text-primary-content !border-primary'"
x-bind:aria-pressed="(active === 'left') ? 'true' : 'false'"
x-on:click="active = 'left'">Left</x-button>
<x-button appearance="outline" color="neutral"
x-bind:class="active === 'center' && '!bg-primary !text-primary-content !border-primary'"
x-bind:aria-pressed="(active === 'center') ? 'true' : 'false'"
x-on:click="active = 'center'">Center</x-button>
<x-button appearance="outline" color="neutral"
x-bind:class="active === 'right' && '!bg-primary !text-primary-content !border-primary'"
x-bind:aria-pressed="(active === 'right') ? 'true' : 'false'"
x-on:click="active = 'right'">Right</x-button>
</x-button-group>
<p class="text-xs text-base-content/60">Selected: <span x-text="active" class="font-medium text-base-content"></span></p>
</div>
<div x-data="{ active: 'center' }" class="flex flex-col gap-4">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0 [&>[aria-pressed=true]:not(:last-child)]:border-r-[length:var(--border)] [&>[aria-pressed=true]+*]:border-l-0 [&>*]:hover:bg-base-200 [&>*]:hover:text-base-content [&>*]:hover:border-base-300">
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer" x-bind:class="active === 'left' && '!bg-primary !text-primary-content !border-primary'" x-bind:aria-pressed="(active === 'left') ? 'true' : 'false'" x-on:click="active = 'left'">Left</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer" x-bind:class="active === 'center' && '!bg-primary !text-primary-content !border-primary'" x-bind:aria-pressed="(active === 'center') ? 'true' : 'false'" x-on:click="active = 'center'">Center</button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer" x-bind:class="active === 'right' && '!bg-primary !text-primary-content !border-primary'" x-bind:aria-pressed="(active === 'right') ? 'true' : 'false'" x-on:click="active = 'right'">Right</button>
</div>
<p class="text-xs text-base-content/60">
Selected: <span x-text="active" class="font-medium text-base-content"></span>
</p>
</div>
icon-only buttons — bundle square icon buttons (toolbar style)
<x-button-group>
<x-button class="w-10 h-10 !p-0" appearance="outline" color="neutral" aria-label="bold">
<x-i type="text-bold" variant="linear" class="w-4 h-4" />
</x-button>
<x-button class="w-10 h-10 !p-0" appearance="outline" color="neutral" aria-label="italic">
<x-i type="text-italic" variant="linear" class="w-4 h-4" />
</x-button>
<x-button class="w-10 h-10 !p-0" appearance="outline" color="neutral" aria-label="underline">
<x-i type="text-underline" variant="linear" class="w-4 h-4" />
</x-button>
</x-button-group>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0 [&>[aria-pressed=true]:not(:last-child)]:border-r-[length:var(--border)] [&>[aria-pressed=true]+*]:border-l-0 [&>*]:hover:bg-base-200 [&>*]:hover:text-base-content [&>*]:hover:border-base-300">
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer w-10 h-10 !p-0" aria-label="bold"><svg class="w-4 h-4" viewbox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-width="1.5" d="M5 4.609A2.61 2.61 0 0 1 7.609 2H12a5 5 0 0 1 0 10H5zM5 12h9a5 5 0 0 1 0 10H7.059A2.06 2.06 0 0 1 5 19.941z"></path></svg></button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer w-10 h-10 !p-0" aria-label="italic"><svg class="w-4 h-4" viewbox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3 22h12M9 2h12M9 22l6-20"></path></svg></button>
<button class="inline-flex items-center justify-center whitespace-nowrap font-medium tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 rounded-[var(--radius-field)] border-[length:var(--border)] h-[var(--h-field-md)] px-[var(--px-field-md)] text-[length:var(--text-field-md)] gap-2 bg-transparent text-base-content border-base-content/10 hover:bg-base-content hover:text-base-100 focus-visible:ring-base-content cursor-pointer w-10 h-10 !p-0" aria-label="underline"><svg class="w-4 h-4" viewbox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 21h16M4 3v6a8 8 0 1 0 16 0V3"></path></svg></button>
</div>