Radio Group
Free · MITHeadless, accessible, and styled entirely through the attribute surface below — bring your own CSS system, or start from the reference theme.
Install
Without a flag you get no styling at all — plain HTML carrying the attribute surface below. --theme copies the same theme in two dialects;--bridge lumos re-points either one onto Lumos for Astro's tokens (it needs a theme to re-point, and Lumos itself, already in your project).
Unstyled — behavior only, you write the CSS
npx astrocraft-ui add forms/radio-groupPlain-CSS theme — no build step
npx astrocraft-ui add forms/radio-group --theme cssTailwind theme — needs Tailwind v4
npx astrocraft-ui add forms/radio-group --theme tailwindPlain-CSS theme, re-pointed onto Lumos tokens
npx astrocraft-ui add forms/radio-group --theme css --bridge lumosTailwind theme, re-pointed onto Lumos tokens
npx astrocraft-ui add forms/radio-group --theme tailwind --bridge lumosLive demo
RadioGroup & CheckboxGroup
Both are real fieldsets, so the legend names the group. The checkbox group’s first box is the select-all — tick one child and it goes indeterminate, the state HTML has no attribute for.
Attribute surface
With no class-merging machinery, these attributes are the whole extension point. State is a data-attribute or a native attribute; visibility is the hiddenattribute. Generated from source by pnpm slots.
| Component | Slots | Variants | Runtime state | Native state |
|---|---|---|---|---|
| `RadioGroup.astro` | `radio-group` `radio-group-label` | `data-orientation`: `vertical` · `horizontal` | — | — |
| `RadioGroupIndicator.astro` | `radio-dot` | — | — | — |
| `RadioGroupItem.astro` | `radio-group-item` `radio-group-item-label` | — | — | — |
Source
What the command copies — 4 files, alias-free so the copy lands standing alone. This is the whole component, shown without its comments; the files you install keep them, with the reasoning behind every rule.
---
import type { HTMLAttributes } from "astro/types";
type Props = HTMLAttributes<"fieldset"> & {
label?: string;
orientation?: "vertical" | "horizontal";
};
const { label, orientation = "vertical", class: className, ...rest } = Astro.props;
---
<fieldset
class={className}
role="radiogroup"
data-slot="radio-group"
data-orientation={orientation}
{...rest}
>
{label && <legend data-slot="radio-group-label">{label}</legend>}
<slot />
</fieldset>
---
import type { HTMLAttributes } from "astro/types";
type Props = HTMLAttributes<"span">;
const { class: className, ...rest } = Astro.props;
---
<span class={className} data-slot="radio-dot" aria-hidden="true" {...rest}></span>
---
import type { HTMLAttributes } from "astro/types";
import Radio from "../../forms/radio";
type Props = HTMLAttributes<"input"> & { name: string; value: string };
const { name, value, class: className, ...rest } = Astro.props;
---
<label data-slot="radio-group-item">
<Radio name={name} value={value} class={className} {...rest} />
<span data-slot="radio-group-item-label"><slot /></span>
</label>
import RadioGroup from "./RadioGroup.astro";
import RadioGroupIndicator from "./RadioGroupIndicator.astro";
import RadioGroupItem from "./RadioGroupItem.astro";
export { RadioGroup, RadioGroupIndicator, RadioGroupItem };
export default RadioGroup;
What you get
The component source, copied into your project by npx astrocraft-ui add forms/radio-group — no package dependency, no CSS to fight. Whatever the paid blocks compose, this is it.