Toggle Group
Two-state buttons orchestrated by <mo-toggle-group>: single-select or multi-select in joined segments.
INSTALL
1pnpm dlx @sayagodev/mo add toggle-groupOr import the files from the package (no copy):
1import "@sayagodev/mo/css/toggle-group.css";2import "@sayagodev/mo/js/toggle-group.js";
EXAMPLES
Multiple icons
1<mo-toggle-group type="multiple" data-variant="outline">2 <button type="button" value="bold" aria-label="Toggle bold" aria-pressed="true">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="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" /></svg>4 </button>5 <button type="button" value="italic" aria-label="Toggle italic" aria-pressed="false">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"><line x1="19" x2="10" y1="4" y2="4" /><line x1="14" x2="5" y1="20" y2="20" /><line x1="15" x2="9" y1="4" y2="20" /></svg>7 </button>8 <button type="button" value="strikethrough" aria-label="Toggle strikethrough" aria-pressed="false">9 <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="M16 4H9a3 3 0 0 0-2.83 4" /><path d="M14 12a4 4 0 0 1 0 8H6" /><line x1="4" x2="20" y1="12" y2="12" /></svg>10 </button>11</mo-toggle-group>12
Outline single
1<mo-toggle-group type="single" data-variant="outline">2 <button type="button" value="all" aria-pressed="true">All</button>3 <button type="button" value="missed" aria-pressed="false">Missed</button>4</mo-toggle-group>5
Sizes
1<div class="vstack gap-4 align-left">2 <mo-toggle-group type="single" data-variant="outline">3 <button type="button" class="small" value="top" aria-pressed="true">Top</button>4 <button type="button" class="small" value="bottom" aria-pressed="false">Bottom</button>5 <button type="button" class="small" value="left" aria-pressed="false">Left</button>6 <button type="button" class="small" value="right" aria-pressed="false">Right</button>7 </mo-toggle-group>8 <mo-toggle-group type="single" data-variant="outline">9 <button type="button" value="top" aria-pressed="false">Top</button>10 <button type="button" value="bottom" aria-pressed="true">Bottom</button>11 <button type="button" value="left" aria-pressed="false">Left</button>12 <button type="button" value="right" aria-pressed="false">Right</button>13 </mo-toggle-group>14 <mo-toggle-group type="single" data-variant="outline">15 <button type="button" class="large" value="top" aria-pressed="false">Top</button>16 <button type="button" class="large" value="bottom" aria-pressed="false">Bottom</button>17 <button type="button" class="large" value="left" aria-pressed="false">Left</button>18 <button type="button" class="large" value="right" aria-pressed="true">Right</button>19 </mo-toggle-group>20</div>21
Spacing
1<mo-toggle-group type="single" data-variant="outline" data-spacing="2">2 <button type="button" class="small" value="top" aria-pressed="true">Top</button>3 <button type="button" class="small" value="bottom" aria-pressed="false">Bottom</button>4 <button type="button" class="small" value="left" aria-pressed="false">Left</button>5 <button type="button" class="small" value="right" aria-pressed="false">Right</button>6</mo-toggle-group>7
Vertical
1<div class="vstack gap-4 align-left">2 <mo-toggle-group type="multiple" data-orientation="vertical" data-spacing="2">3 <button type="button" value="bold" aria-label="Toggle bold" aria-pressed="true">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="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" /></svg>5 </button>6 <button type="button" value="italic" aria-label="Toggle italic" aria-pressed="true">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"><line x1="19" x2="10" y1="4" y2="4" /><line x1="14" x2="5" y1="20" y2="20" /><line x1="15" x2="9" y1="4" y2="20" /></svg>8 </button>9 <button type="button" value="strikethrough" aria-label="Toggle strikethrough" aria-pressed="false">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="M16 4H9a3 3 0 0 0-2.83 4" /><path d="M14 12a4 4 0 0 1 0 8H6" /><line x1="4" x2="20" y1="12" y2="12" /></svg>11 </button>12 </mo-toggle-group>13</div>14
Disabled
1<mo-toggle-group type="single" data-variant="outline" disabled>2 <button type="button" value="bold" aria-label="Toggle bold" aria-pressed="false" disabled>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="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" /></svg>4 </button>5 <button type="button" value="italic" aria-label="Toggle italic" aria-pressed="false" disabled>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"><line x1="19" x2="10" y1="4" y2="4" /><line x1="14" x2="5" y1="20" y2="20" /><line x1="15" x2="9" y1="4" y2="20" /></svg>7 </button>8 <button type="button" value="strikethrough" aria-label="Toggle strikethrough" aria-pressed="false" disabled>9 <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="M16 4H9a3 3 0 0 0-2.83 4" /><path d="M14 12a4 4 0 0 1 0 8H6" /><line x1="4" x2="20" y1="12" y2="12" /></svg>10 </button>11</mo-toggle-group>12
Font weight selector
1<mo-toggle-group type="single" data-variant="outline" data-spacing="2">2 <button type="button" value="light" aria-pressed="false">3 <span class="flex flex-col items-center">Aa<br />Light</span>4 </button>5 <button type="button" value="normal" aria-pressed="true">6 <span class="flex flex-col items-center">Aa<br />Normal</span>7 </button>8 <button type="button" value="medium" aria-pressed="false">9 <span class="flex flex-col items-center">Aa<br />Medium</span>10 </button>11 <button type="button" value="bold" aria-pressed="false">12 <strong>Aa</strong><br />Bold13 </button>14</mo-toggle-group>15
USAGE
1<mo-toggle-group type="multiple">2 <button type="button" value="bold" aria-pressed="true"><svg … /></button>3 <button type="button" value="italic" aria-pressed="false"><svg … /></button>4</mo-toggle-group>
API
NAMEKINDDESCRIPTION
<mo-toggle-group>elementOrchestrator over button[aria-pressed] children
typeattributesingle (default) · multiple
collapsibleattributeSingle groups allow unpressing the active item
[data-orientation="vertical"] / [data-spacing]attributeStack or separate segments
mo-toggle-changeelementCustom event, detail { values } after every change
--mo-toggle-bgtokenPressed segment surface (default muted, like shadcn data-state=on)
--mo-toggle-group-gaptokenGap between separated segments (data-spacing 1·2)
FILES
src/css/toggle-group.csssrc/js/toggle-group.jsInstall:
mo add toggle-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--radiusComponent hooks
--mo-toggle-bg--mo-toggle-group-gapPreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.