react-collapse
Collapse component with CSS transition for elements with variable and dynamic height.
react-collapse
Demo
CSS required
:warning: ️You need to add style (transition) in your own stylesheet to add animation. Here is an example.
<style>
.collapse-css-transition {
transition: height 280ms cubic-bezier(0.4, 0, 0.2, 1);
}
</style>
Alternatively, you can add it using the transition
prop.
Installation for React 16.8+
- UMD minified ~2.3 kb, gzipped ~1.1 kb
- Module minified ~2.9 kb, gzipped ~1.1 kb
- CJS minified ~2.0 kb, gzipped ~1.0 kb
npm i -D @kunukn/react-collapse
Installation for React 16.3+
Avoid it if possible. This is no longer maintained.
- UMD minified ~5.8 kb, gzipped ~2.1 kb
npm i -D @kunukn/react-collapse@^1
Minimal toggle content component example.
import { Collapse } from '@kunukn/react-collapse'
import React from 'react'
export default function MyComponent() {
const [isOpen, setIsOpen] = React.useState(false)
const onToggle = () => setIsOpen((s) => !s)
return (
<div className="my-component">
<button onClick={onToggle}> Toggle </button>
<Collapse
isOpen={isOpen}
transition="height 300ms cubic-bezier(0.4, 0, 0.2, 1)"
>
<p> Hello world </p>
</Collapse>
</div>
)
}
import { Collapse } from '@kunukn/react-collapse'
import '@kunukn/react-collapse/dist/react-collapse.css'
import type { CollapseProps } from '@kunukn/react-collapse/dist/react-collapse.d.ts'
const { Collapse } = require('@kunukn/react-collapse/dist/react-collapse.cjs')
Properties
Prop | Type | Default |
---|
isOpen | boolean | false |
children | node | function | |
render | function | |
className | string | collapse-css-transition |
transition | string | |
elementType | string | div |
collapseHeight | string | 0px |
onChange | function | |
onInit | function | |
addState | boolean | false |
noAnim | boolean | false |
overflowOnExpanded | boolean | false |
isOpen
: boolean
Expands or collapses content.
children
: node | function
Render the children.
const MyComponent = ({ isOpen }) => (
<Collapse isOpen={isOpen}>
<p>Paragraph of text.</p>
<p>Another paragraph is also OK.</p>
<p>Images and any other content are ok too.</p>
<img src="cutecat.gif" />
</Collapse>
)
Render content using the render-props pattern.
const MyComponent = ({ isOpen }) => (
<Collapse isOpen={isOpen}>
{(state) => (
<div className={`using-collapse-state-to-add-css-class ${state}`}>
<p>I know the collapse state: {state}</p>
</div>
)}
</Collapse>
)
render
: function
Render content using the render-props pattern.
const MyComponent = ({ isOpen }) => {
const render = (state) => (
<div className={`using-collapse-state-to-add-css-class ${state}`}>
<p>I know the collapse state: {state}</p>
</div>
)
return <Collapse isOpen={isOpen} render={render} />
}
There are four possible collapse states: collapsed
, collapsing
, expanded
, expanding
.
className
: string
You can specify a custom className. The default value is collapse-css-transition
. Remember to add CSS transition if a className is provided.
transition
: string
You can also specify a CSS transition inline by using the transition
prop.
const MyComponent = ({ isOpen, duration = '290ms' }) => (
<Collapse
transition={`height ${duration} cubic-bezier(.4, 0, .2, 1)`}
isOpen={isOpen}
>
<p>Paragraph of text</p>
</Collapse>
)
elementType
: string
You can specify the HTML element type for the collapse component. By default, the element type is a div
element.
const MyComponent = ({ isOpen }) => (
<Collapse elementType="article" isOpen={isOpen}>
<p>Paragraph of text inside an article element</p>
</Collapse>
)
collapseHeight
: string
You can specify the collapse height in CSS unit to partially show some content.
const MyComponent = ({ isOpen }) => (
<Collapse collapseHeight="40px" isOpen={isOpen}>
<p>A long paragraph of text inside an article element</p>
</Collapse>
)
onChange
: function
Callback function for when the transition changes.
const MyComponent = ({ isOpen }) => {
const onChange = ({ state, style }) => {
}
return (
<Collapse onChange={onChange} isOpen={isOpen}>
<p>A long paragraph of text inside an article element</p>
</Collapse>
)
}
onInit
: function
Similar to onChange but only invoked on DOM mounted.
This is an example that starts collapsed and expands on mount.
const MyComponent = () => {
const [isOpen, setIsOpen] = React.useState(false)
const onInit = ({ state, style, node }) => {
setIsOpen(true)
}
return (
<div>
<button onClick={() => setIsOpen((state) => !state)}> Toggle </button>
<Collapse onInit={onInit} isOpen={isOpen}>
<p>A long paragraph of text inside an article element</p>
</Collapse>
</div>
)
}
addState
: boolean
If added, then one of the class names will be appended to the component depending on the state.
--c-collapsed
--c-collapsing
--c-expanded
--c-expanding
noAnim
: boolean
If added, then there will be no collapse animation. State changes between collapsed
and expanded
.
overflowOnExpanded
: boolean
If added, then overflow: hidden
style will not be added when the state is expanded
.
Custom props
Collapse
applies custom props such as aria-
and data-
attributes to the component's rendered DOM element. For example, this can be used to set the aria-hidden
attribute:
const MyComponent = ({ isOpen }) => (
<Collapse aria-hidden={isOpen ? 'false' : 'true'} isOpen={isOpen}>
<p>Paragraph of text</p>
</Collapse>
)
Or you could specify a specific transitionDuration.
const collapseStyles = { transitionDuration: '270ms' }
const MyComponent = ({ isOpen }) => (
<Collapse style={collapseStyles} isOpen={isOpen}>
<p>Paragraph of text</p>
</Collapse>
)
Development
To run development
npm start
git clone [repo]
cd [repo]
npm i
npm start
- To develop and play around:
npm start
- To build the bundle:
npm run build
CDN
https://unpkg.com/@kunukn/react-collapse/
<link
rel="stylesheet"
href="https://unpkg.com/@kunukn/react-collapse/dist/react-collapse.css"
/>
<script src="https://unpkg.com/@kunukn/react-collapse"></script>
NPM
https://www.npmjs.com/package/@kunukn/react-collapse
Supported browsers
Modern browsers (Edge, Firefox, Chrome, Safari, etc).
Supported React versions
- React version 16.3+ : use Collapse version 1
- React version 16.8+ : use Collapse version 2+
Used React 16.3 life-cycles
- render (uses the style states to invoke CSS transition)
- componentDidMount (initial expanded or collapsed state)
- getDerivedStateFromProps (detect if isOpen props have changed and apply a new collapse state)
- componentDidUpdate (update style states from the four possible collapse states)
Used React 16.8+ hooks
- useState
- useEffect
- useRef
- useCallback
- useReducer
Design goals
- let the browser handle the animation using CSS height transition
- minimal in file size
- minimalistic API - only have a Collapse component which updates on isOpen props
- flexible - provide your own markup, styling and easing
- interruptible - can be reversed during movement
- inert - when collapsed you should tab over the collapsed component
- availability - from cdn or npm install
- collapsible on height only
This was created with heavy inspiration from
https://github.com/SparebankenVest/react-css-collapse 🎆
A version also exists for Vue
https://github.com/kunukn/vue-height-collapsible