Newer
Older
import React, { useEffect, useRef, useState } from "react";
import "./collapsible.css";
interface CollapsibleProps {
open?: boolean;
header: string | React.ReactNode;
children?: React.ReactNode | React.ReactNode[];
heightTransition?: boolean;
// Implementation details partially from https://medium.com/edonec/build-a-react-collapsible-component-from-scratch-using-react-hooks-typescript-73dfd02c9208
function Collapsible({
open,
header,
children,
color = "gray",
const [isOpen, setIsOpen] = useState(open);
const [height, setHeight] = useState<number | undefined>(
open ? undefined : 0
);
const toggleOpen = () => {
setIsOpen((prev) => !prev);
};
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!height || !isOpen || !ref.current) return undefined;
const resizeObserver = new ResizeObserver((el) => {
setHeight(el[0].contentRect.height);
});
resizeObserver.observe(ref.current);
return () => {
resizeObserver.disconnect();
};
}, [height, isOpen]);
useEffect(() => {
if (isOpen) setHeight(ref.current?.getBoundingClientRect().height);
else setHeight(0);
}, [isOpen]);
const borderBottom = "1px solid " + color;
return (
<>
<div className={"collapsible-card"}>
<div>
<button
type="button"
className={`collapsible-button ${
isOpen ? "" : "collapsed"
}`}
onClick={toggleOpen}
<div className={`collapsible-content ${heightTransition ? "collapsible-transition-height" : ""}`} style={{ height }}>