Button Group
Buttons, selects, inputs and dropdown triggers joined into one segmented control with shared hairlines.
INSTALL
1pnpm dlx @sayagodev/mo add button-groupOr import the files from the package (no copy):
1import "@sayagodev/mo/css/button-group.css";EXAMPLES
Demo
1<div data-button-group role="group" aria-label="Email actions">2 <div data-button-group>3 <button type="button" class="outline icon" aria-label="Go back">4 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg>5 </button>6 </div>7 <div data-button-group>8 <button type="button" class="outline">Archive</button>9 <button type="button" class="outline">Report</button>10 </div>11 <div data-button-group>12 <button type="button" class="outline">Snooze</button>13 <mo-dropdown>14 <button type="button" class="outline icon" popovertarget="bg-demo-menu" aria-label="More options">15 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="5" cy="12" r="1" /><circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" /></svg>16 </button>17 <menu popover id="bg-demo-menu">18 <button role="menuitem" type="button">19 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 13V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h14" /><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" /><path d="m16 19 2 2 4-4" /></svg>20 Mark as Read21 </button>22 <button role="menuitem" type="button">23 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="20" height="5" x="2" y="3" rx="1" /><path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8" /><path d="M10 12h4" /></svg>24 Archive25 </button>26 <hr />27 <button role="menuitem" type="button" popovertarget="bg-demo-sub">28 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z" /><circle cx="7.5" cy="7.5" r=".5" fill="currentColor" /></svg>29 Label As…30 </button>31 <menu popover id="bg-demo-sub">32 <button role="menuitemradio" type="button" aria-checked="true">Personal</button>33 <button role="menuitemradio" type="button" aria-checked="false">Work</button>34 <button role="menuitemradio" type="button" aria-checked="false">Other</button>35 </menu>36 <hr />37 <button role="menuitem" type="button" data-variant="danger">38 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" /><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /><line x1="10" x2="10" y1="11" y2="17" /><line x1="14" x2="14" y1="11" y2="17" /></svg>39 Trash40 </button>41 </menu>42 </mo-dropdown>43 </div>44</div>45
Orientation
1<div data-button-group role="group" aria-label="Media controls" data-orientation="vertical">2 <button type="button" class="outline icon" aria-label="Add">3 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>4 </button>5 <button type="button" class="outline icon" aria-label="Remove">6 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /></svg>7 </button>8</div>9<div data-button-group role="group" aria-label="List actions" data-orientation="vertical">10 <button type="button" class="outline">Day</button>11 <button type="button" class="outline">Month</button>12 <button type="button" class="outline">Year</button>13</div>14
Sizes
1<div class="vstack gap-6">2 <div data-button-group role="group" aria-label="Small group">3 <button type="button" class="outline small">Small</button>4 <button type="button" class="outline small">Button</button>5 <button type="button" class="outline small">Group</button>6 <button type="button" class="outline small icon" aria-label="Add">7 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>8 </button>9 </div>10 <div data-button-group role="group" aria-label="Default group">11 <button type="button" class="outline">Default</button>12 <button type="button" class="outline">Button</button>13 <button type="button" class="outline">Group</button>14 <button type="button" class="outline icon" aria-label="Add">15 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>16 </button>17 </div>18 <div data-button-group role="group" aria-label="Large group">19 <button type="button" class="outline large">Large</button>20 <button type="button" class="outline large">Button</button>21 <button type="button" class="outline large">Group</button>22 <button type="button" class="outline large icon" aria-label="Add">23 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>24 </button>25 </div>26</div>27
Nested
1<div data-button-group role="group" aria-label="Composer">2 <div data-button-group>3 <button type="button" class="outline icon" aria-label="New message">4 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>5 </button>6 </div>7 <div data-button-group>8 <div data-input-group>9 <input placeholder="Send a message..." aria-label="Message" />10 <span data-addon>11 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 10v3" /><path d="M6 6v11" /><path d="M10 3v18" /><path d="M14 8v7" /><path d="M18 5v13" /><path d="M22 10v3" /></svg>12 </span>13 </div>14 </div>15</div>16
Separator & split
1<div data-button-group role="group" aria-label="Clipboard">2 <button type="button" data-variant="secondary" class="small">Copy</button>3 <hr data-separator />4 <button type="button" data-variant="secondary" class="small">Paste</button>5</div>6<div data-button-group role="group" aria-label="Create">7 <button type="button" data-variant="secondary">New</button>8 <hr data-separator />9 <button type="button" data-variant="secondary" class="icon" aria-label="More">10 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>11 </button>12</div>13
With dropdown
Snooze
1<div data-button-group role="group" aria-label="Follow">2 <mo-dropdown>3 <button type="button" class="outline" popovertarget="bg-dd-menu">Follow</button>4 <menu popover id="bg-dd-menu">5 <button role="menuitem" type="button">Today</button>6 <button role="menuitem" type="button">7 Tomorrow8 <span data-shortcut>⌘T</span>9 </button>10 <hr />11 <button role="menuitem" type="button">This week</button>12 <button role="menuitem" type="button">This month</button>13 </menu>14 </mo-dropdown>15 <mo-dropdown>16 <button type="button" class="outline" popovertarget="bg-dd-more" aria-label="More options">17 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>18 </button>19 <menu popover id="bg-dd-more">20 <div data-label>Snooze</div>21 <button role="menuitem" type="button">For 1 hour</button>22 <button role="menuitem" type="button">Until tomorrow</button>23 <hr />24 <button role="menuitem" type="button">Unfollow</button>25 </menu>26 </mo-dropdown>27</div>28
With select
1<div data-button-group role="group" aria-label="Amount">2 <div data-button-group>3 <mo-select data-placeholder="$">4 <button type="button" popovertarget="bg-currency" data-select-trigger aria-label="Currency"></button>5 <ul popover id="bg-currency" class="popover" role="listbox">6 <li><button type="button" role="option" value="$" aria-selected="true">$ USD</button></li>7 <li><button type="button" role="option" value="€">€ EUR</button></li>8 <li><button type="button" role="option" value="£">£ GBP</button></li>9 </ul>10 </mo-select>11 <input placeholder="10.00" inputmode="decimal" pattern="[0-9]*" aria-label="Amount" />12 </div>13 <div data-button-group>14 <button type="button" class="outline icon" aria-label="Send">15 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg>16 </button>17 </div>18</div>19
With input
1<div class="hstack gap-6">2 <div data-button-group role="group" aria-label="Search">3 <input placeholder="Search..." aria-label="Search" />4 <button type="button" class="outline icon" aria-label="Search">5 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>6 </button>7 </div>8 <div data-button-group role="group" aria-label="Create">9 <button type="button" data-variant="secondary">Button</button>10 <button type="button" data-variant="secondary" class="icon" aria-label="Add">11 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>12 </button>13 </div>14</div>15
Text segment
Production
Environment
1<div data-button-group role="group" aria-label="Deployment">2 <span data-button-group-text>Production</span>3 <button type="button" class="outline">Deploy</button>4 <mo-dropdown>5 <button type="button" class="outline icon" popovertarget="bg-env-menu" aria-label="Environment options">6 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>7 </button>8 <menu popover id="bg-env-menu">9 <div data-label>Environment</div>10 <button role="menuitemradio" type="button" aria-checked="true">Production</button>11 <button role="menuitemradio" type="button" aria-checked="false">Staging</button>12 <button role="menuitemradio" type="button" aria-checked="false">Development</button>13 </menu>14 </mo-dropdown>15</div>16
Popover
Start a new task with Copilot
Describe your task in natural language.
Copilot will open a pull request for review.
1<div data-button-group role="group" aria-label="Copilot">2 <button type="button" class="outline">3 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path d="M2 14h2" /><path d="M20 14h2" /><path d="M15 13v2" /><path d="M9 13v2" /></svg>4 Copilot5 </button>6 <button type="button" class="outline icon" popovertarget="bg-copilot-pop" aria-label="Open popover">7 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>8 </button>9</div>10<div popover id="bg-copilot-pop" class="popover">11 <div class="vstack gap-4">12 <div class="vstack gap-1">13 <div data-title>Start a new task with Copilot</div>14 <p data-description>Describe your task in natural language.</p>15 </div>16 <label class="sr-only" for="bg-copilot-task">Task description</label>17 <textarea id="bg-copilot-task" placeholder="I need to..."></textarea>18 <p data-description>Copilot will open a pull request for review.</p>19 </div>20</div>21
USAGE
1<div role="group" data-button-group>2 <button class="outline">Day</button>3 <button class="outline">Month</button>4 <hr data-separator />5 <span data-button-group-text>2026</span>6</div>
API
NAMEKINDDESCRIPTION
[data-button-group]attributeSelects the component on any wrapper
data-orientationattributevertical stacks the join on the block axis
hr[data-separator]element1px divider between segments
[data-button-group-text]attributeMuted bordered label segment
--mo-button-group-*tokenGap/divider hooks
FILES
src/css/button-group.cssInstall:
mo add button-groupTHEMING · PLAYGROUND
This is the exact component from the examples above, wearing a completely different theme. Edit the tokens and --mo-* hooks in the editor — autocomplete knows them all — and the preview obeys in real time. Your CSS always wins.
Global tokens
--border--foreground--input--muted--muted-foreground--radiusComponent hooks
--mo-button-group-divider--mo-button-group-gap--mo-button-group-text-padding-x--mo-button-radiusPreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.