1 | # react-collapse
|
2 |
|
3 | Collapse component with CSS transition for elements with variable and dynamic height.
|
4 |
|
5 | [![npm version](https://img.shields.io/npm/v/@kunukn/react-collapse.svg?style=flat-square)](https://www.npmjs.com/package/@kunukn/react-collapse)
|
6 | [![npm downloads](https://img.shields.io/npm/dm/@kunukn/react-collapse.svg?style=flat-square)](https://www.npmjs.com/package/@kunukn/react-collapse)
|
7 | [![gzip](https://img.shields.io/bundlephobia/minzip/@kunukn/react-collapse.svg)](https://bundlephobia.com/result?p=@kunukn/react-collapse)
|
8 | [![license](https://img.shields.io/github/license/kunukn/react-collapse.svg)](https://github.com/kunukn/react-collapse/blob/master/LICENSE)
|
9 |
|
10 | react-collapse
|
11 |
|
12 | ![logo](logo/collapse.svg "logo")
|
13 |
|
14 | # Demo
|
15 |
|
16 | - <a href="https://codepen.io/kunukn/full/ebMryW" target="_blank">simple - codepen</a>
|
17 | - <a href="https://codepen.io/kunukn/full/xmjRNo" target="_blank">accordion - codepen</a>
|
18 | - <a href="https://codepen.io/kunukn/full/JwmEYL" target="_blank">read more - codepen</a>
|
19 | - <a href="https://codesandbox.io/s/k1439yw2v5" target="_blank">codesandbox - collapsibles</a>
|
20 | - <a href="https://codesandbox.io/s/react-collapse-expand-all-collapse-all-0h4mc">codesandbox expand-all</a>
|
21 | - <a href="https://codesandbox.io/s/collapse-with-emotion-css-prototype-euqy2">codesandbox CSS-in-JS integration example</a>
|
22 | - <a href="https://kunukn.github.io/react-collapse" target="_blank">view storybook</a>
|
23 |
|
24 | # CSS required
|
25 |
|
26 | :warning: ️You need to add style (transition) in your own stylesheet to add animation. Here is an example.
|
27 |
|
28 | ```html
|
29 | <style>
|
30 | .collapse-css-transition {
|
31 | transition: height 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
32 | }
|
33 | </style>
|
34 | ```
|
35 |
|
36 | Alternatively you can add it using the `transition` prop.
|
37 |
|
38 | ## Installation for React 16.8+
|
39 |
|
40 | UMD minified 3.8kb, gzipped 1.7kb
|
41 |
|
42 | ```bash
|
43 | npm i @kunukn/react-collapse
|
44 | # or
|
45 | # yarn add @kunukn/react-collapse
|
46 | ```
|
47 |
|
48 | ## Installation for React 16.3+
|
49 |
|
50 | UMD minified 5.8kb, gzipped 2.1kb
|
51 |
|
52 | ```bash
|
53 | npm i @kunukn/react-collapse@^1
|
54 | # or
|
55 | # yarn add @kunukn/react-collapse@^1
|
56 | ```
|
57 |
|
58 | ```jsx
|
59 | import Collapse from "@kunukn/react-collapse";
|
60 | // or with require syntax
|
61 | // const Collapse = require("@kunukn/react-collapse");
|
62 |
|
63 | const MyComponent = () => (
|
64 | <Collapse isOpen={true || false}>
|
65 | <div>Your content</div>
|
66 | </Collapse>
|
67 | );
|
68 | ```
|
69 |
|
70 | ## Properties
|
71 |
|
72 | | Prop | Type | Default |
|
73 | | ------------------ | ---------------- | ----------------------- |
|
74 | | isOpen | boolean | false |
|
75 | | children | node \| function | |
|
76 | | render | function | |
|
77 | | className | string | collapse-css-transition |
|
78 | | transition | string | |
|
79 | | elementType | string | div |
|
80 | | collapseHeight | string | 0px |
|
81 | | onChange | function | |
|
82 | | onInit | function | |
|
83 | | addState | boolean | false |
|
84 | | noAnim | boolean | false |
|
85 | | overflowOnExpanded | boolean | false |
|
86 |
|
87 | <br>
|
88 |
|
89 | #### `isOpen` : boolean
|
90 |
|
91 | Expands or collapses content.
|
92 |
|
93 | #### `children` : node | function
|
94 |
|
95 | Render the children.
|
96 |
|
97 | ```jsx
|
98 | const MyComponent = ({ isOpen }) => (
|
99 | <Collapse isOpen={isOpen}>
|
100 | <p>Paragraph of text.</p>
|
101 | <p>Another paragraph is also OK.</p>
|
102 | <p>Images and any other content are ok too.</p>
|
103 | <img src="cutecat.gif" />
|
104 | </Collapse>
|
105 | );
|
106 | ```
|
107 |
|
108 | Render content using the [render-props pattern](https://reactjs.org/docs/render-props.html).
|
109 |
|
110 | ```jsx
|
111 | const MyComponent = ({ isOpen }) => (
|
112 | <Collapse isOpen={isOpen}>
|
113 | {state => (
|
114 | <div className={`using-collapse-state-to-add-css-class ${state}`}>
|
115 | <p>I know the collapse state: {state}</p>
|
116 | </div>
|
117 | )}
|
118 | </Collapse>
|
119 | );
|
120 | ```
|
121 |
|
122 | #### `render` : function
|
123 |
|
124 | Render content using the render-props pattern.
|
125 |
|
126 | ```jsx
|
127 | const MyComponent = ({ isOpen }) => {
|
128 | const render = state => (
|
129 | <div className={`using-collapse-state-to-add-css-class ${state}`}>
|
130 | <p>I know the collapse state: {state}</p>
|
131 | </div>
|
132 | );
|
133 | return <Collapse isOpen={isOpen} render={render} />;
|
134 | };
|
135 | ```
|
136 |
|
137 | There are four possible collapse states: `collapsed`, `collapsing`, `expanded`, `expanding`.
|
138 |
|
139 | #### `className` : string
|
140 |
|
141 | You can specify a custom className. The default value is `collapse-css-transition`. Remember to add CSS transition if a className is provided.
|
142 |
|
143 | #### `transition` : string
|
144 |
|
145 | You can also specify a CSS transition inline by using the `transition` prop.
|
146 |
|
147 | ```jsx
|
148 | const MyComponent = ({ isOpen, duration = "290ms" }) => (
|
149 | <Collapse
|
150 | transition={`height ${duration} cubic-bezier(.4, 0, .2, 1)`}
|
151 | isOpen={isOpen}
|
152 | >
|
153 | <p>Paragraph of text</p>
|
154 | </Collapse>
|
155 | );
|
156 | ```
|
157 |
|
158 | #### `elementType` : string
|
159 |
|
160 | You can specify the HTML element type for the collapse component. By default the element type is a `div` element.
|
161 |
|
162 | ```jsx
|
163 | const MyComponent = ({ isOpen }) => (
|
164 | <Collapse elementType="article" isOpen={isOpen}>
|
165 | <p>Paragraph of text inside an article element</p>
|
166 | </Collapse>
|
167 | );
|
168 | ```
|
169 |
|
170 | #### `collapseHeight` : string
|
171 |
|
172 | You can specify the collapse height in CSS unit to partially show some content.
|
173 |
|
174 | ```jsx
|
175 | const MyComponent = ({ isOpen }) => (
|
176 | <Collapse collapseHeight="40px" isOpen={isOpen}>
|
177 | <p>A long paragraph of text inside an article element</p>
|
178 | </Collapse>
|
179 | );
|
180 | ```
|
181 |
|
182 | #### `onChange` : function
|
183 |
|
184 | Callback function for when the transition changes.
|
185 |
|
186 | ```jsx
|
187 | const MyComponent = ({ isOpen }) => {
|
188 | const onChange = ({ state, style }) => {
|
189 | /*
|
190 | state: string = the state of the collapse component.
|
191 | style: object = styles that are applied to the component.
|
192 | */
|
193 | };
|
194 |
|
195 | return (
|
196 | <Collapse onChange={onChange} isOpen={isOpen}>
|
197 | <p>A long paragraph of text inside an article element</p>
|
198 | </Collapse>
|
199 | );
|
200 | };
|
201 | ```
|
202 |
|
203 | #### `onInit` : function
|
204 |
|
205 | Similar to onChange but only invoked on DOM mounted.<br/>
|
206 | This is an example that starts collapsed and expands on mount.
|
207 |
|
208 | ```jsx
|
209 | const MyComponent = () => {
|
210 |
|
211 | const [isOpen, setIsOpen] = React.useState(false);
|
212 |
|
213 | const onInit = ({ state, style, node }) => {
|
214 | /*
|
215 | node: HTMLElement = the DOM node of the component.
|
216 | */
|
217 |
|
218 | setIsOpen(true);
|
219 | };
|
220 |
|
221 | return (
|
222 | <div>
|
223 | <button onClick={() => setIsOpen(state => !state)}> Toggle </button>
|
224 | <Collapse onInit={onInit} isOpen={isOpen}>
|
225 | <p>A long paragraph of text inside an article element</p>
|
226 | </Collapse>
|
227 | </div>
|
228 | );
|
229 | };
|
230 | ```
|
231 |
|
232 | #### `addState` : boolean
|
233 |
|
234 | If added, then one of the class names will be appended to the component depending on the state.
|
235 |
|
236 | ```
|
237 | --c-collapsed
|
238 | --c-collapsing
|
239 | --c-expanded
|
240 | --c-expanding
|
241 | ```
|
242 |
|
243 | #### `noAnim` : boolean
|
244 |
|
245 | If added, then there will be no collapse animation. State changes between `collapsed` and `expanded`.
|
246 |
|
247 | #### `overflowOnExpanded` : boolean
|
248 |
|
249 | If added, then `overflow: hidden` style will not be added when the state is `expanded`.
|
250 |
|
251 | #### Custom props
|
252 |
|
253 | `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:
|
254 |
|
255 | ```jsx
|
256 | const MyComponent = ({ isOpen }) => (
|
257 | <Collapse aria-hidden={isOpen ? "false" : "true"} isOpen={isOpen}>
|
258 | <p>Paragraph of text</p>
|
259 | </Collapse>
|
260 | );
|
261 | ```
|
262 |
|
263 | Or you could specify a specific transitionDuration.
|
264 |
|
265 | ```jsx
|
266 | const collapseStyles = { transitionDuration: "270ms" };
|
267 |
|
268 | const MyComponent = ({ isOpen }) => (
|
269 | <Collapse style={collapseStyles} isOpen={isOpen}>
|
270 | <p>Paragraph of text</p>
|
271 | </Collapse>
|
272 | );
|
273 | ```
|
274 |
|
275 | ## Development and testing
|
276 |
|
277 | To run development
|
278 |
|
279 | `npm start` or `yarn start`
|
280 |
|
281 | ```bash
|
282 | git clone [repo]
|
283 | cd [repo]
|
284 | npm i
|
285 | npm start
|
286 | open http://localhost:6007
|
287 | npm test
|
288 | ```
|
289 |
|
290 | or with **yarn**
|
291 |
|
292 | ```bash
|
293 | git clone [repo]
|
294 | cd [repo]
|
295 | yarn
|
296 | yarn start
|
297 | open http://localhost:6007
|
298 | yarn test
|
299 | ```
|
300 |
|
301 | - To develop and play around: `yarn start`
|
302 | - To build the bundle: `yarn build`
|
303 | - To validate the bundle: `yarn validate`
|
304 |
|
305 | To run example covering all features, use `npm run storybook` or `yarn storybook`.
|
306 |
|
307 | # CDN
|
308 |
|
309 | https://unpkg.com/@kunukn/react-collapse/
|
310 |
|
311 | ```html
|
312 | <link
|
313 | rel="stylesheet"
|
314 | href="https://unpkg.com/@kunukn/react-collapse/dist/Collapse.umd.css"
|
315 | />
|
316 | <script src="https://unpkg.com/@kunukn/react-collapse/dist/Collapse.umd.js"></script>
|
317 |
|
318 | <script>
|
319 | var Collapse = window.Collapse;
|
320 | </script>
|
321 | ```
|
322 |
|
323 | # Supported browsers
|
324 |
|
325 | IE11 + Modern browsers
|
326 |
|
327 | # Supported React versions
|
328 |
|
329 | - React version 16.3+ : use Collapse version 1
|
330 | - React version 16.8+ : use Collapse version 2+
|
331 |
|
332 | # Used React 16.3 life-cycles
|
333 |
|
334 | - **render** (uses the style states to invoke CSS transition)
|
335 | - **componentDidMount** (initial expanded or collapsed state)
|
336 | - **getDerivedStateFromProps** (detect if isOpen props has changed and apply a new collapse state)
|
337 | - **componentDidUpdate** (update style states from the four possible collapse states)
|
338 |
|
339 | # Used React 16.8 hooks
|
340 |
|
341 | - **useState**
|
342 | - **useEffect**
|
343 | - **useRef**
|
344 | - **useCallback**
|
345 | - **useReducer**
|
346 |
|
347 | # Design goals
|
348 |
|
349 | - let the browser handle the animation using CSS height transition
|
350 | - minimal in file size
|
351 | - minimalistic API - only have a Collapse component which updates on isOpen props
|
352 | - flexible - provide your own markup, styling and easing
|
353 | - interruptible - can be reversed during movement
|
354 | - inert - when collapsed you should tab over the collapsed component
|
355 | - availability - from cdn or npm install
|
356 | - Collapsible on height only
|
357 |
|
358 | # This was created with heavy inspiration from
|
359 |
|
360 | [https://github.com/SparebankenVest/react-css-collapse](https://github.com/SparebankenVest/react-css-collapse) 🎆
|