COMPONENTS/INPUTS
Radio group.
One choice from a considered set.
In practice
Provide a name and aria-label on RadioGroup. Give each RadioGroupItem a unique value and visible label.
Installation
Install Coal once. Components and TypeScript declarations are included. React 19 and React DOM 19 are peer dependencies.
Terminal · local package
npm install http://localhost:3100/downloads/chlohal-coal-ui-0.5.0.tgzThis installs the local package. It is not yet published on npm. See installation for stylesheet setup and integration.
Usage
example.tsx
"use client";
import * as React from "react";
import "@chlohal/coal-ui/styles.css";
import { RadioGroup, RadioGroupItem } from "@chlohal/coal-ui";
export default function Example() {
return (<RadioGroup defaultValue="personal" aria-label="Workspace plan">
{["personal", "studio", "team"].map((s) => (<label key={s}>
<RadioGroupItem value={s}/>
{s}
</label>))}
</RadioGroup>);
}
Source
The original Coal implementation. Use the package export to integrate it.
packages/react/src/radio-group.tsx
"use client";
import * as React from "react";
import { cn, useValue, useRequired } from "./internal.js";
const Context = React.createContext<
| {
value: string;
set: (value: string) => void;
name: string;
disabled?: boolean;
required?: boolean;
}
| undefined
>(undefined);
export type RadioGroupProps = Omit<
React.ComponentPropsWithRef<"div">,
"defaultValue" | "onChange"
> & {
value?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
name?: string;
disabled?: boolean;
required?: boolean;
};
export function RadioGroup({
value,
defaultValue = "",
onValueChange,
name,
disabled,
required,
children,
className,
...props
}: RadioGroupProps) {
const id = React.useId();
const [v, set] = useValue(value, defaultValue, onValueChange);
return (
<Context.Provider
value={{ value: v, set, name: name ?? id, disabled, required }}
>
<div
role="radiogroup"
className={cn("coal-radio-group", className)}
{...props}
>
{children}
</div>
</Context.Provider>
);
}
export function RadioGroupItem({
value,
disabled,
onChange,
className,
...props
}: Omit<React.ComponentPropsWithRef<"input">, "type" | "value"> & {
value: string;
}) {
const c = useRequired(Context, "RadioGroupItem");
return (
<input
{...props}
type="radio"
className={cn("coal-radio", className)}
name={c.name}
value={value}
required={c.required}
disabled={disabled || c.disabled}
checked={c.value === value}
onChange={(e) => {
onChange?.(e);
if (!e.defaultPrevented) c.set(value);
}}
/>
);
}
Accessibility checklist
- Provide an accessible name for controls, including icon-only buttons.
- Check keyboard navigation, visible focus and disabled states in your application.
- Do not rely on color alone to communicate status.