Collapsible components with variable heights are hard, but not anymore, this example will make you rethink how you develop this in your company library from now on! Let's get into it!
Step 1: Create the Collapsible Component
For this example, I'm using styled-components but feel free to use plane css, or any css-in-js library you prefer
// Collapsible component
interface Animation {
duration?: number;
ease?: string;
}
interface CollapsibleProps {
children: React.ReactNode;
open: boolean;
animation?: Animation;
}
const defaultAnimationValues = {
duration: 0.2,
ease: "ease-in-out"
};
const CollapsibleWrapper = styled.div<{ open: boolean; animation: Animation }>`
display: grid;
grid-template-rows: ${(props) => (props.open ? "1fr" : "0fr")};
opacity: 0;
transition: all ${(props) => props.animation.duration}s
${(props) => props.animation.ease};
opacity: ${(props) => (props.open ? 1 : 0)};
`;
const CollapsibleInner = styled.div`
overflow: hidden;
`;
export const Collapsible: React.FC<CollapsibleProps> = ({
children,
open,
animation = defaultAnimationValues
}) => {
return (
<CollapsibleWrapper open={open} animation={animation}>
<CollapsibleInner>{children}</CollapsibleInner>
</CollapsibleWrapper>
);
};
I added extra props to control animation timing and speed to make more customisable, beyond that there's not to much here here except for one detail...
grid-template-rows: ${(props) => (props.open ? "1fr" : "0fr")};
This is the secret sauce! This line will actually open and close the Collapsible component adjusting the wrapper component height based on the children height!
Step2: Using the component
This is also incredible straightforward, set the state for toggling "show" and render whatever you want inside your new Collapsible component!
// App component
export default function App() {
const [show, setShow] = React.useState(false);
return (
<div className="App">
<button onClick={() => setShow(!show)}>click</button>
<Collapsible open={show}>
<div className="bg-gray-100 py-4">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</Collapsible>
</div>
);
}
Now you can stop using those crazy height-controlled components! Wrap the code from the next codesanbox
Top comments (0)