Skip to main content
useCollapse manages vertical expand/collapse transitions and returns transition-aware props to spread onto the collapsible element.

Usage

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Demo() {
  const [expanded, setExpanded] = useState(false);
  const { getCollapseProps } = useCollapse({ expanded });

  return (
    <div>
      <button onClick={() => setExpanded((e) => !e)}>
        {expanded ? 'Collapse' : 'Expand'}
      </button>
      <div {...getCollapseProps()}>
        <div style={{ padding: 20 }}>
          <p>This content will smoothly expand and collapse</p>
          <p>The height is automatically calculated</p>
        </div>
      </div>
    </div>
  );
}

API Reference

Parameters

input
UseCollapseInput
required
Collapse configuration object.
input.expanded
boolean
required
Whether the content should be expanded.
input.transitionDuration
number
Transition duration in milliseconds. When omitted, duration is calculated from content height.
input.transitionTimingFunction
string
default:"ease"
CSS timing function for the transition.
input.onTransitionEnd
() => void
Callback fired when the height transition finishes.
input.onTransitionStart
() => void
Callback fired when a transition starts.
input.keepMounted
boolean
default:"false"
When true, collapsed content stays mounted and is hidden with styles.

Returns

state
'entering' | 'entered' | 'exiting' | 'exited'
Current transition state.
getCollapseProps
(input?: GetCollapsePropsInput) => GetCollapsePropsReturnValue
Function that returns props to spread onto the collapsible element.

Accordion

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Accordion() {
  const [openItem, setOpenItem] = useState<number | null>(null);

  const items = [
    { title: 'Section 1', content: 'Content for section 1' },
    { title: 'Section 2', content: 'Content for section 2' },
    { title: 'Section 3', content: 'Content for section 3' },
  ];

  return (
    <div>
      {items.map((item, index) => (
        <AccordionItem
          key={index}
          title={item.title}
          content={item.content}
          expanded={openItem === index}
          onToggle={() => setOpenItem(openItem === index ? null : index)}
        />
      ))}
    </div>
  );
}

function AccordionItem({ title, content, expanded, onToggle }) {
  const { getCollapseProps } = useCollapse({ expanded });

  return (
    <div>
      <button onClick={onToggle}>{title}</button>
      <div {...getCollapseProps()}>
        <div style={{ padding: 16 }}>{content}</div>
      </div>
    </div>
  );
}

Custom Duration

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Demo() {
  const [expanded, setExpanded] = useState(false);
  
  const { getCollapseProps } = useCollapse({
    expanded,
    transitionDuration: 1000,
    transitionTimingFunction: 'ease-in-out',
  });

  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>Toggle</button>
      <div {...getCollapseProps()}>
        <div style={{ padding: 20 }}>Slow transition content</div>
      </div>
    </div>
  );
}

Keep Mounted

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Demo() {
  const [expanded, setExpanded] = useState(false);
  
  const { getCollapseProps, state } = useCollapse({
    expanded,
    keepMounted: true, // Content stays in DOM when collapsed
  });

  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>Toggle</button>
      <p>State: {state}</p>
      <div {...getCollapseProps()}>
        <div style={{ padding: 20 }}>This content stays mounted</div>
      </div>
    </div>
  );
}

With Callbacks

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Demo() {
  const [expanded, setExpanded] = useState(false);
  
  const { getCollapseProps } = useCollapse({
    expanded,
    onTransitionStart: () => console.log('Transition started'),
    onTransitionEnd: () => console.log('Transition ended'),
  });

  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>Toggle</button>
      <div {...getCollapseProps()}>
        <div style={{ padding: 20 }}>Content with callbacks</div>
      </div>
    </div>
  );
}

Custom Styles

import { useCollapse } from '@kuzenbo/hooks';
import { useState } from 'react';

function Demo() {
  const [expanded, setExpanded] = useState(false);
  const { getCollapseProps } = useCollapse({ expanded });

  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>Toggle</button>
      <div
        {...getCollapseProps({
          style: {
            border: '1px solid #ccc',
            borderRadius: 4,
          },
        })}
      >
        <div style={{ padding: 20 }}>Styled collapse content</div>
      </div>
    </div>
  );
}

Build docs developers (and LLMs) love