Skip to content

useCollapse

Category
Export Size
1.10 kB
Last Changed
5 days ago

Animate an element's height between 0 and its measured content height.

Demo

Usage

tsx
import { 
useCollapse
} from '@reause/core'
import {
useState
} from 'react'
function
Demo
() {
const [
expanded
,
setExpanded
] =
useState
(false)
const {
state
,
getCollapseProps
} =
useCollapse
({
expanded
})
return ( <> <
button
onClick={() =>
setExpanded
(
prev
=> !
prev
)}>Toggle</button>
<div {...getCollapseProps()}> <
p
>Collapsible content</p>
</div> </> ) }

Important: Re-evaluated on every render. Spread getCollapseProps() directly on the element instead of storing its result.


Behavior

getCollapseProps(input?)

Returns element props required to control accessibility and height animation: { style, ref, onTransitionEnd, 'aria-hidden', inert }

  • style: Merges input.style with internal styles. Internal transition styles (height, overflow, display) override input.style, while preserving custom border and padding.
  • ref: Merges internal node measurements with input.ref (supports Callback & Object Ref).
  • onTransitionEnd: Internal transition completion handler.

Warning: Do not override onTransitionEnd without chaining the original handler; otherwise, state will remain stuck in entering or exiting.

  • aria-hidden & inert: Set to !expanded. When collapsed, content is hidden from accessibility trees and interactive focus.

Key Options

keepMounted (boolean, default: false)

Controls style behavior when collapsed (does not control DOM unmounting):

OptionCollapsed StylesBehavior
false (default){ height: 0, overflow: 'hidden', display: 'none' }Removed from layout & rendered tree
true{ height: 0, overflow: 'hidden' }Retains layout box in DOM tree

Unmounting the DOM node remains the responsibility of the consumer.

transitionDuration (number, optional)

If omitted, duration is auto-calculated via getAutoHeightDuration(height) based on scrollHeight:

ts
const 
constant
= height / 36
const
duration
=
Math
.
round
((4 + 15 *
constant
** 0.25 +
constant
/ 5) * 10)

Unmeasurable heights (or non-numeric values) evaluate to 0ms to prevent bogus animation timing.


Internal Technical Notes

  • Synchronous Layout Measurement: Uses React DOM's flushSync to measure and repaint the element synchronously before applying the exit transition, preventing height-jump glitches during collapse.
  • Event Handler Stability: Callback props (onTransitionStart, onTransitionEnd) use latest-value refs rather than useEffectEvent, ensuring compatibility with React >= 18.0.
  • Utilities Exported:
  • getElementHeight(ref): Returns scrollHeight or 'auto'.
  • isMeasured(size): Type guard identifying transitionable elements (0 is treated as unmeasurable).

Type Declarations

Toggle
ts
export interface UseCollapseInput {
    expanded: boolean;
    transitionDuration?: number;
    transitionTimingFunction?: string;
    onTransitionEnd?: () => void;
    onTransitionStart?: () => void;
    keepMounted?: boolean;
}

export type UseCollapseState = 'entering' | 'entered' | 'exiting' | 'exited'

export interface UseCollapseReturnValue {
    state: UseCollapseState;
    getCollapseProps: (input?: GetCollapsePropsInput) => GetCollapsePropsReturnValue;
}

interface GetCollapsePropsInput {
    style?: CSSProperties;
    ref?: Ref<HTMLDivElement>;
}

interface GetCollapsePropsReturnValue {
    'aria-hidden': boolean;
    'inert': boolean;
    'ref': RefCallback<HTMLDivElement>;
    'onTransitionEnd': (event: TransitionEvent<Element>) => void;
    'style': CSSProperties;
}

export function getElementHeight(elementRef: RefObject<HTMLElement | null>)

export function isMeasured(size: number | string): size is number

export function useCollapse({ transitionDuration, transitionTimingFunction = 'ease', onTransitionEnd, onTransitionStart, expanded, keepMounted, }: UseCollapseInput): UseCollapseReturnValue

Source

Source · Demo · Mantine

Contributors

hairyf

Changelog

v0.1.6 on
2a0a4 - fix(meta): name each useCollapse export in its own provenance claim (#971)
861a6 - feat(core): add useCollapse (#934)

Released under the MIT License. v0.1.8