COMPONENTS/DATA DISPLAY
Collapsible.
Details, on your terms.
In practice
Built with React and Base UI. Styled with Tailwind. Yours to change.
Use open/onOpenChange for controlled state. Trigger and content are automatically associated.
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 { ChevronDown } from "lucide-react";
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@chlohal/coal-ui";
export default function Example() {
return (<Collapsible>
<CollapsibleTrigger>
A few more details <ChevronDown size={14}/>
</CollapsibleTrigger>
<CollapsibleContent>
Built with React and Base UI. Styled with Tailwind. Yours to change.
</CollapsibleContent>
</Collapsible>);
}
Source
The original Coal implementation. Use the package export to integrate it.
packages/react/src/collapsible.tsx
"use client";
import * as React from "react";
import {
Action,
cn,
useValue,
useRequired,
type ActionProps,
} from "./internal.js";
const Context = React.createContext<
{ open: boolean; set: (v: boolean) => void; id: string } | undefined
>(undefined);
export type CollapsibleProps = React.ComponentPropsWithRef<"div"> & {
open?: boolean;
defaultOpen?: boolean;
onOpenChange?: (value: boolean) => void;
};
export function Collapsible({
open,
defaultOpen = false,
onOpenChange,
children,
...props
}: CollapsibleProps) {
const [v, set] = useValue(open, defaultOpen, onOpenChange);
const id = React.useId();
return (
<Context.Provider value={{ open: v, set, id }}>
<div {...props}>{children}</div>
</Context.Provider>
);
}
export function CollapsibleTrigger({ onClick, ...props }: ActionProps) {
const c = useRequired(Context, "CollapsibleTrigger");
return (
<Action
{...props}
aria-expanded={c.open}
aria-controls={c.id}
onClick={(e) => {
onClick?.(e);
if (!e.defaultPrevented) c.set(!c.open);
}}
/>
);
}
export function CollapsibleContent({
className,
...props
}: React.ComponentPropsWithRef<"div">) {
const c = useRequired(Context, "CollapsibleContent");
return (
<div
{...props}
id={c.id}
hidden={!c.open}
className={cn("coal-collapsible-content", className)}
/>
);
}
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.