UNPKG

@kunukn/react-collapse

Version:

Collapse library based on CSS transition for React

383 lines (280 loc) 10.8 kB
# react-collapse Collapse component with CSS transition for elements with variable and dynamic height. [![npm version](https://img.shields.io/npm/v/@kunukn/react-collapse.svg?style=flat-square)](https://www.npmjs.com/package/@kunukn/react-collapse) [![npm downloads](https://img.shields.io/npm/dm/@kunukn/react-collapse.svg?style=flat-square)](https://www.npmjs.com/package/@kunukn/react-collapse) [![gzip](https://img.shields.io/bundlephobia/minzip/@kunukn/react-collapse.svg)](https://bundlephobia.com/result?p=@kunukn/react-collapse) [![license](https://img.shields.io/github/license/kunukn/react-collapse.svg)](https://github.com/kunukn/react-collapse/blob/master/LICENSE) react-collapse ![logo](logo/collapse.svg 'logo') # Demo - <a href="https://codepen.io/kunukn/full/ebMryW" target="_blank">simple - codepen</a> - <a href="https://codepen.io/kunukn/full/xmjRNo" target="_blank">accordion - codepen</a> - <a href="https://codepen.io/kunukn/full/JwmEYL" target="_blank">read more - codepen</a> - <a href="https://stackblitz.com/edit/vitejs-vite-qfvnck" target="_blank">simple - edit stackblitz</a> - <a href="https://codesandbox.io/s/k1439yw2v5" target="_blank">codesandbox - collapsibles</a> - <a href="https://codesandbox.io/s/react-collapse-expand-all-collapse-all-0h4mc">codesandbox expand-all</a> - <a href="https://codesandbox.io/s/collapse-with-emotion-css-prototype-euqy2">codesandbox CSS-in-JS integration example</a> - <a href="https://kunukn.github.io/react-collapse" target="_blank">view storybook</a> # CSS required :warning: ️You need to add style (transition) in your own stylesheet to add animation. Here is an example. ```html <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 ```bash npm i -D @kunukn/react-collapse # or # yarn add -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 ```bash npm i -D @kunukn/react-collapse@^1 # or # yarn add -D @kunukn/react-collapse@^1 ``` Minimal toggle content component example. ```jsx // Notice how you import it, changed since ver 3. 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> ) } ``` ```jsx // The possible imports import { Collapse } from '@kunukn/react-collapse' // UMD import '@kunukn/react-collapse/dist/react-collapse.css' // CSS import type { CollapseProps } from '@kunukn/react-collapse/dist/react-collapse.d.ts' // TS const { Collapse } = require('@kunukn/react-collapse/dist/react-collapse.cjs') // CommonJS ``` ## 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 | <br> #### `isOpen` : boolean Expands or collapses content. #### `children` : node | function Render the children. ```jsx 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](https://reactjs.org/docs/render-props.html). ```jsx 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. ```jsx 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. ```jsx 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. ```jsx 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. ```jsx 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. ```jsx const MyComponent = ({ isOpen }) => { const onChange = ({ state, style }) => { /* state: string = the state of the collapse component. style: object = styles that are applied to the component. */ } 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.<br/> This is an example that starts collapsed and expands on mount. ```jsx const MyComponent = () => { const [isOpen, setIsOpen] = React.useState(false) const onInit = ({ state, style, node }) => { /* node: HTMLElement = the DOM node of the component. */ 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: ```jsx const MyComponent = ({ isOpen }) => ( <Collapse aria-hidden={isOpen ? 'false' : 'true'} isOpen={isOpen}> <p>Paragraph of text</p> </Collapse> ) ``` Or you could specify a specific transitionDuration. ```jsx const collapseStyles = { transitionDuration: '270ms' } const MyComponent = ({ isOpen }) => ( <Collapse style={collapseStyles} isOpen={isOpen}> <p>Paragraph of text</p> </Collapse> ) ``` ## Development To run development `npm start` ```bash 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/ ```html <link rel="stylesheet" href="https://unpkg.com/@kunukn/react-collapse/dist/react-collapse.css" /> <!-- UMD --> <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](https://github.com/SparebankenVest/react-css-collapse) 🎆 # A version also exists for Vue https://github.com/kunukn/vue-height-collapsible