Skip to content

Instantly share code, notes, and snippets.

@mech
Created November 24, 2025 08:39
Show Gist options
  • Select an option

  • Save mech/1e1baa80b3119708338e6986369f00eb to your computer and use it in GitHub Desktop.

Select an option

Save mech/1e1baa80b3119708338e6986369f00eb to your computer and use it in GitHub Desktop.
Simple Accordion
"use client";
import { createContext, useCallback, useContext } from "react";
const AccordionContext = createContext({
value: [],
onValueChange: () => {},
});
const ItemContext = createContext({
value: null,
});
export const Root = ({
children,
value,
onValueChange,
multiple = false,
...props
}) => {
const handleValueChange = useCallback(
(newValue) => {
if (multiple) {
onValueChange((prev) =>
prev.includes(newValue)
? prev.filter((v) => v !== newValue)
: [...prev, newValue],
);
} else {
onValueChange((prev) => (prev[0] === newValue ? [] : [newValue]));
}
},
[onValueChange, multiple],
);
return (
<AccordionContext.Provider
value={{ value, onValueChange: handleValueChange }}
>
<div {...props}>{children}</div>
</AccordionContext.Provider>
);
};
export const Item = ({ value, ...props }) => {
return (
<ItemContext.Provider value={{ value }}>
<div {...props} />
</ItemContext.Provider>
);
};
export const Trigger = ({ children, ...props }) => {
const { value: itemValue } = useContext(ItemContext);
return (
<AccordionContext.Consumer>
{({ value, onValueChange }) => (
<button onClick={() => onValueChange(itemValue)} {...props}>
{children} ({value.includes(itemValue) ? "O" : "C"}) v={itemValue}
</button>
)}
</AccordionContext.Consumer>
);
};
export const Content = ({ ...props }) => {
const { value: itemValue } = useContext(ItemContext);
return (
<AccordionContext.Consumer>
{({ value }) => value.includes(itemValue) && <div {...props} />}
</AccordionContext.Consumer>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment