Home / Docs / PixelRadioGroup PixelRadioGroup Single-select grouped radios with a pixel dot indicator, fieldset/legend semantics, and tone + surface variants.
Controlled — value + onChange (React), v-model (Vue), [(value)] or forms (Angular) — over a list of options. Renders as a real <fieldset> with role="radiogroup" and a <legend> from label. Seven tones and pixel/linear surfaces share the kit-wide design tokens. Optional name emits a hidden input so it serializes inside native forms. disabled cascades to every option button (not just visually). Status stable Category forms Since v1.0.0 API React Vue Angular
import { PixelRadioGroup } from '@pxlkit/ui-kit';Prop Type Default Description label* (required) string— Legend rendered above the group. value* (required) string— Currently-selected option value. options* (required) Option[]— Radio items. onChange* (required) (next: string) => void— Fires with the new value when the user picks a radio. disabledbooleanfalseDisables every radio in the group. tone'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral''cyan'Visual tone for the selected radio. Default: 'cyan'. surface'pixel' | 'linear'— Surface variant. Inherits from PxlKitSurfaceProvider when omitted. namestring— Form-serialization name. requiredboolean— Marks the field as required for native form validation.
ref points to its element (HTMLFieldSetElement).
Accessibility WCAG target: 2.1 AA
Wrapped in a <fieldset role="radiogroup"> with <legend> derived from label and aria-disabled / aria-required mirroring the props. Each option is a <button role="radio"> with aria-checked reflecting selection. When name is set a hidden <input> mirrors the current value so the group participates in native <form> submissions. Keyboard focus shows on the focused radio's indicator: a ring in the tone on the linear surface, the indicator's edge on the pixel surface, whose cut corners would clip a ring.
Keyboard Key Action When Tab Moves focus into the radio group and on to the next focusable element after the last option. — Space Activates the focused radio option (native <button> behavior). — Enter Activates the focused radio option (native <button> behavior). —
Usage React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Default() {
const [value, setValue] = useState('free');
return (
<PixelRadioGroup
label="Plan"
value={value}
options={PLANS}
onChange={setValue}
/>
);
}Examples Default React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Default() {
const [value, setValue] = useState('free');
return (
<PixelRadioGroup
label="Plan"
value={value}
options={PLANS}
onChange={setValue}
/>
);
}Controlled React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Controlled() {
const [value, setValue] = useState('pro');
return (
<div className="space-y-2">
<PixelRadioGroup
label="Selected plan"
value={value}
options={PLANS}
onChange={setValue}
tone="cyan"
/>
<p className="text-xs text-retro-muted">Picked: {value}</p>
</div>
);
}Tones React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Tones() {
const [value, setValue] = useState('pro');
return (
<div className="grid grid-cols-2 gap-6">
<PixelRadioGroup label="Neutral" tone="neutral" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Green" tone="green" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Cyan" tone="cyan" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Gold" tone="gold" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Red" tone="red" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Purple" tone="purple" value={value} options={PLANS} onChange={setValue} />
<PixelRadioGroup label="Pink" tone="pink" value={value} options={PLANS} onChange={setValue} />
</div>
);
}Surfaces React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Surfaces() {
const [pixel, setPixel] = useState('pro');
const [linear, setLinear] = useState('pro');
return (
<div className="grid grid-cols-2 gap-6">
<PixelRadioGroup
label="Pixel surface"
surface="pixel"
value={pixel}
options={PLANS}
onChange={setPixel}
/>
<PixelRadioGroup
label="Linear surface"
surface="linear"
value={linear}
options={PLANS}
onChange={setLinear}
/>
</div>
);
}Disabled React Vue Angular
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Disabled() {
return (
<PixelRadioGroup
label="Plan (locked)"
value="pro"
options={PLANS}
onChange={() => {}}
disabled
/>
);
}Required React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function Required() {
const [value, setValue] = useState('');
return (
<PixelRadioGroup
label="Pick a plan to continue"
value={value}
options={PLANS}
onChange={setValue}
required
/>
);
}With form name React Vue Angular
import { useState } from 'react';
import { PixelRadioGroup } from '@pxlkit/ui-kit';
const PLANS = [
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'team', label: 'Team' },
];
export function WithFormName() {
const [value, setValue] = useState('pro');
return (
<form>
<PixelRadioGroup
label="Plan"
name="plan"
value={value}
options={PLANS}
onChange={setValue}
required
/>
</form>
);
}