Radio Group
Native radios grouped by name. Fieldset/legend titles the group; [data-field] carries hints and errors.
INSTALL
1pnpm dlx @sayagodev/mo add formOr import the files from the package (no copy):
1import "@sayagodev/mo/css/form.css";EXAMPLES
Basic
1<div class="vstack gap-2">2 <label><input type="radio" name="rg-demo" value="default" /> Default</label>3 <label><input type="radio" name="rg-demo" value="comfortable" checked /> Comfortable</label>4 <label><input type="radio" name="rg-demo" value="compact" /> Compact</label>5</div>6
With descriptions
Standard spacing for most use cases.
More space between elements.
Minimal spacing for dense layouts.
1<div class="vstack gap-4">2 <div class="flex items-start gap-2">3 <input type="radio" id="rd-desc-default" name="rg-desc" value="default" />4 <div class="vstack gap-1">5 <label for="rd-desc-default">Default</label>6 <small class="text-light">Standard spacing for most use cases.</small>7 </div>8 </div>9 <div class="flex items-start gap-2">10 <input type="radio" id="rd-desc-comfortable" name="rg-desc" value="comfortable" checked />11 <div class="vstack gap-1">12 <label for="rd-desc-comfortable">Comfortable</label>13 <small class="text-light">More space between elements.</small>14 </div>15 </div>16 <div class="flex items-start gap-2">17 <input type="radio" id="rd-desc-compact" name="rg-desc" value="compact" />18 <div class="vstack gap-1">19 <label for="rd-desc-compact">Compact</label>20 <small class="text-light">Minimal spacing for dense layouts.</small>21 </div>22 </div>23</div>24
Disabled item
1<div class="vstack gap-2">2 <label><input type="radio" name="rg-disabled" value="option1" disabled /> Disabled</label>3 <label><input type="radio" name="rg-disabled" value="option2" checked /> Option 2</label>4 <label><input type="radio" name="rg-disabled" value="option3" /> Option 3</label>5</div>6
Fieldset with hint
1<fieldset>2 <legend>Subscription Plan</legend>3 <p class="text-light">Yearly and lifetime plans offer significant savings.</p>4 <div class="vstack gap-2 mt-2">5 <label><input type="radio" name="rg-plan" value="monthly" checked /> Monthly ($9.99/month)</label>6 <label><input type="radio" name="rg-plan" value="yearly" /> Yearly ($99.99/year)</label>7 <label><input type="radio" name="rg-plan" value="lifetime" /> Lifetime ($299.99)</label>8 </div>9</fieldset>10
Invalid group
1<fieldset aria-invalid="true">2 <legend>Notification Preferences</legend>3 <p class="text-light">Choose how you want to receive notifications.</p>4 <div data-field class="mt-2">5 <div class="vstack gap-2">6 <label><input type="radio" name="rg-notif" value="email" checked aria-invalid="true" /> Email only</label>7 <label><input type="radio" name="rg-notif" value="sms" aria-invalid="true" /> SMS only</label>8 <label><input type="radio" name="rg-notif" value="both" aria-invalid="true" /> Both Email & SMS</label>9 </div>10 <small class="error">Select a notification preference to continue.</small>11 </div>12</fieldset>13
Choice cards
1<div class="vstack gap-4">2 <label class="flex items-center justify-between gap-4">3 <span class="vstack gap-1">4 <strong>Plus</strong>5 <span class="text-light">For individuals and small teams.</span>6 </span>7 <input type="radio" name="rg-card" value="plus" checked />8 </label>9 <label class="flex items-center justify-between gap-4">10 <span class="vstack gap-1">11 <strong>Pro</strong>12 <span class="text-light">For growing businesses.</span>13 </span>14 <input type="radio" name="rg-card" value="pro" />15 </label>16 <label class="flex items-center justify-between gap-4">17 <span class="vstack gap-1">18 <strong>Enterprise</strong>19 <span class="text-light">For large teams and enterprises.</span>20 </span>21 <input type="radio" name="rg-card" value="enterprise" />22 </label>23</div>24
USAGE
1<fieldset>2 <legend>Subscription plan</legend>3 <div class="vstack gap-2 mt-2">4 <label><input type="radio" name="plan" checked /> Monthly</label>5 <label><input type="radio" name="plan" /> Yearly</label>6 </div>7</fieldset>
API
NAMEKINDDESCRIPTION
input[type=radio]elementRound dot indicator
nameattributeGroups radios natively
fieldset / legendelementTitled group container
[data-field] + small.errorclassGroup error reveal on invalid
FILES
src/css/form.cssInstall:
mo add formTHEMING · 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
--background--border--destructive--foreground--input--muted--muted-foreground--primary--primary-foreground--radius--ringComponent hooks
--mo-field-gap--mo-input-padding-x--mo-input-radius--mo-slider-thumb-bg--mo-switch-thumb--mo-switch-widthPreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.