COMPONENTS/INPUTS
Toggle group.
A few choices, kept together.
In practice
Supply an array of strings with defaultValue or value/onValueChange. Single or multiple mode; arrow keys move focus, Space toggles. Add aria-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 { ToggleGroup, ToggleGroupItem } from "@chlohal/coal-ui";
import { Bold, Italic } from "lucide-react";
export default function Example() {
return (<ToggleGroup type="multiple" defaultValue={["bold"]} aria-label="Text formatting">
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
<ToggleGroupItem value="underline">Underline</ToggleGroupItem>
</ToggleGroup>);
}
Source
The original Coal implementation. Use the package export to integrate it.
packages/react/src/toggle-group.tsx
"use client";
import * as React from "react";
import { cn, useRequired, useValue, moveFocus } from "./internal.js";
import { Toggle, type ToggleProps } from "./toggle.js";
const Context = React.createContext<
{ value: string[]; set: (v: string) => void; disabled?: boolean } | undefined
>(undefined);
export type ToggleGroupProps = Omit<
React.ComponentPropsWithRef<"div">,
"defaultValue" | "onChange"
> & {
type?: "single" | "multiple";
value?: string[];
defaultValue?: string[];
onValueChange?: (v: string[]) => void;
disabled?: boolean;
orientation?: "horizontal" | "vertical";
};
export function ToggleGroup({
type = "single",
value,
defaultValue = [],
onValueChange,
disabled,
orientation = "horizontal",
children,
className,
onKeyDown,
...props
}: ToggleGroupProps) {
const [v, set] = useValue(value, defaultValue, onValueChange);
return (
<Context.Provider
value={{
value: v,
disabled,
set: (item) =>
set(
v.includes(item)
? v.filter((x) => x !== item)
: type === "single"
? [item]
: [...v, item],
),
}}
>
<div
role="group"
className={cn("coal-toggle-group", className)}
data-orientation={orientation}
{...props}
onKeyDown={(e) => {
onKeyDown?.(e);
if (!e.defaultPrevented) moveFocus(e, "button", orientation);
}}
>
{children}
</div>
</Context.Provider>
);
}
export function ToggleGroupItem({
value,
disabled,
...props
}: Omit<
ToggleProps,
"value" | "pressed" | "defaultPressed" | "onPressedChange"
> & { value: string }) {
const c = useRequired(Context, "ToggleGroupItem");
return (
<Toggle
{...props}
disabled={disabled || c.disabled}
pressed={c.value.includes(value)}
onPressedChange={() => 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.