npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-fast-collapsible

v1.0.0

Published

A tiny, dependency-free React collapsible that animates to auto height with pure CSS (grid 0fr→1fr) — no JavaScript height measurement, no forced reflows.

Downloads

171

Readme

react-fast-collapsible

npm version minzipped size dependencies license

A tiny, dependency-free React collapsible that animates to height: auto with pure CSS — no JavaScript height measurement, no forced reflows, no layout thrashing.

import { Collapsible } from 'react-fast-collapsible';

<Collapsible open={open}>
  <YourContent />
</Collapsible>;

Motivation

Most React collapsible libraries — including the popular react-collapsible — animate height in JavaScript:

  1. They render the content, then read its scrollHeight from the DOM.
  2. Reading scrollHeight forces the browser to synchronously recalculate layout — a forced reflow (a.k.a. layout thrashing).
  3. They write an explicit pixel height, wait a frame, then transition to the measured value.
  4. Every open/close (and often every content or resize change) repeats this measure-then-write dance on the main thread.

It works, but it has real costs: forced reflows are a well-known performance footgun, the animation can jank on busy pages, content whose height changes is awkward to handle, and you ship a chunk of imperative JavaScript to do something the browser can already do natively.

react-fast-collapsible takes the opposite approach. It animates a CSS Grid row track from 0fr to 1fr:

display: grid;
grid-template-rows: 0fr;             /* closed */
transition: grid-template-rows 300ms;
/* open -> grid-template-rows: 1fr   the row grows to fit the content */

The browser animates the track from zero to the content's intrinsic size — without anyone ever measuring that size in JavaScript. There is no scrollHeight read, so there is no JS-forced reflow. Content of any height (including content that changes) just works, because 1fr resolves to whatever the content needs. The component holds no state, runs no effects, and ships zero dependencies.

The only JavaScript involved is flipping the open boolean — which you were already doing.

Features

  • Zero dependencies, under 1 kB min+gzip.
  • Pure-CSS animation to auto height (CSS grid 0fr/1fr).
  • No forced reflows — nothing reads layout on toggle.
  • Handles content of unknown or dynamic height automatically.
  • Accessible — collapsed content is inert (out of the tab order and the a11y tree).
  • Unstyled and composable — bring Tailwind, plain CSS, or inline styles.
  • First-class TypeScript types, ref forwarding, full div prop passthrough.
  • SSR/RSC-safe, tree-shakeable, ships ESM + CJS.

Installation

npm install react-fast-collapsible
# or
pnpm add react-fast-collapsible
# or
yarn add react-fast-collapsible

Peer dependency: react >= 17.

Usage

Collapsible is controlled — you own the open boolean, so it works with any state source.

import { useState } from 'react';
import { Collapsible } from 'react-fast-collapsible';

export function Example() {
  const [open, setOpen] = useState(false);

  return (
    <div>
      <button onClick={() => setOpen((o) => !o)}>{open ? 'Hide' : 'Show'}</button>

      <Collapsible open={open}>
        <p>Any content — text, images, lists, dynamic height. No measuring required.</p>
      </Collapsible>
    </div>
  );
}

Padding and styling

Put padding/margins on the content via innerClassName / innerStyle, not on the outer container — the outer element must be able to collapse all the way to zero.

<Collapsible open={open} innerStyle={{ padding: 16 }}>
  ...
</Collapsible>

With Tailwind:

<Collapsible open={open} className="rounded-xl border" innerClassName="p-4 text-sm">
  ...
</Collapsible>

Tuning the animation

<Collapsible
  open={open}
  duration={450}
  easing="cubic-bezier(0.22, 1, 0.36, 1)"
  animateOpacity={false}
>
  ...
</Collapsible>

API

| Prop | Type | Default | Description | | ---------------- | ---------------- | -------- | ----------------------------------------------------------------- | | open | boolean | — | Required. Whether the panel is expanded. | | duration | number | 300 | Animation duration in milliseconds. | | easing | string | 'ease' | Any CSS transition-timing-function. | | animateOpacity | boolean | true | Fade the content in/out alongside the height animation. | | innerClassName | string | — | Class on the inner content wrapper — put padding here. | | innerStyle | CSSProperties | — | Inline style on the inner content wrapper. | | className | string | — | Class on the outer (animating) container. | | style | CSSProperties | — | Inline style on the outer container (merged over the defaults). | | ...rest | div attributes | — | Anything else (id, data-*, aria-*, onTransitionEnd, ...). |

The ref is forwarded to the outer container.

How it works

The rendered markup is three nested elements:

<div style="display:grid; grid-template-rows: 0fr -> 1fr; transition">  <!-- animates -->
  <div style="min-height:0; overflow:hidden">                           <!-- clips -->
    <div class="{innerClassName}">{children}</div>                      <!-- your content -->
  </div>
</div>

height: auto is not animatable, but a grid track sized 1fr is — and it resolves to the content's natural height. min-height: 0 lets the row shrink below its content size; overflow: hidden clips the content while it animates. That is the whole trick.

Accessibility

When open is false, the content wrapper receives the inert attribute, so collapsed content cannot be focused, clicked, or read by assistive technology — and it stays out of the tab order — with no JS focus management and no reflow.

react-fast-collapsible vs react-collapsible

| | react-fast-collapsible | react-collapsible | | ---------------------------- | ------------------------- | -------------------------- | | Height animation | CSS grid (browser-native) | JS measures scrollHeight | | Forced reflow on toggle | No | Yes | | Runtime dependencies | 0 | a few | | Dynamic-height content | automatic | needs re-measure | | Bundle size | < 1 kB | larger | | Built-in trigger / accordion | bring your own | included |

react-collapsible bundles a trigger element and more out-of-the-box behavior; react-fast-collapsible is intentionally a minimal, unopinionated primitive that you wire to your own trigger and state.

Browser support

All modern evergreen browsers. The animation relies on animatable grid-template-rows (Chrome 107+, Firefox 66+, Safari 16+) and the inert attribute (Baseline since 2023). In older browsers it degrades gracefully — the panel still opens and closes, just without the smooth tween / inert behavior.

Repository

This package is developed in a pnpm workspace monorepo:

.
├── packages/
│   └── react-fast-collapsible/   # the published library (built with tsdown)
├── examples/
│   └── web/                      # Vite + Tailwind CSS v4 + shadcn/ui + Base UI demo
└── scripts/
    └── copy-readme.mjs           # syncs this README into the package on publish

Development

Requires Node 18+ and pnpm.

pnpm install          # install all workspaces
pnpm dev              # run the example app (consumes the library source with HMR)
pnpm build            # build the library with tsdown -> packages/react-fast-collapsible/dist
pnpm build:example    # type-check and build the example app
pnpm typecheck        # type-check every workspace

The example app under examples/web is built with Vite, Tailwind CSS v4, and shadcn/ui components backed by Base UI primitives. It aliases react-fast-collapsible to the library source, so editing the component hot-reloads instantly in the demo.

Publishing

This README is the single source of truth: scripts/copy-readme.mjs runs in the library's prepack step and copies it into the package directory, so the same content ships to npm.

pnpm build
pnpm release          # pnpm --filter react-fast-collapsible publish

License

MIT © Carlos Dubon