UNPKG

10.5 kBMarkdownView Raw
1<div align="center">
2 <a href="https://github.com/dvtng/react-loading-skeleton">
3 <img src="assets/logo.svg" alt="Logo" width="80" height="80" />
4 </a>
5 <h1 align="center">React Loading Skeleton</h1>
6 <p align="center">
7 Make beautiful, animated loading skeletons that automatically adapt to your app.
8 </p>
9 <h3>
10 <!--<a href="https://dvtng.github.io/react-loading-skeleton">View Live Demo</a> &nbsp;&nbsp;&bull;&nbsp;&nbsp;-->
11 <a href="https://codesandbox.io/s/react-loading-skeleton-3xwil?file=/src/App.tsx">Open on CodeSandbox</a>
12 </h3>
13 <img src="https://media.giphy.com/media/l0Iyk4bAAjac3AU2k/giphy.gif" alt="Gif of the skeleton in action">
14</div>
15
16Learn about the [changes in version
173](https://github.com/dvtng/react-loading-skeleton/releases/tag/v3.0.0), or view
18the [v2
19documentation](https://github.com/dvtng/react-loading-skeleton/tree/v2#readme).
20
21## Basic Usage
22
23Install via one of:
24
25```bash
26yarn add react-loading-skeleton
27npm install react-loading-skeleton
28```
29
30```tsx
31import Skeleton from 'react-loading-skeleton'
32import 'react-loading-skeleton/dist/skeleton.css'
33
34<Skeleton /> // Simple, single-line loading skeleton
35<Skeleton count={5} /> // Five-line loading skeleton
36```
37
38## Principles
39
40### Adapts to the styles you have defined
41
42The `Skeleton` component should be used directly in your components in place of
43content that is loading. While other libraries require you to meticulously craft
44a skeleton screen that matches the font size, line height, and margins of your
45content, the `Skeleton` component is automatically sized to the correct
46dimensions.
47
48For example:
49
50```tsx
51function BlogPost(props) {
52 return (
53 <div>
54 <h1>{props.title || <Skeleton />}</h1>
55 {props.body || <Skeleton count={10} />}
56 </div>
57 );
58}
59```
60
61...will produce correctly-sized skeletons for the heading and body without any
62further configuration.
63
64This ensures the loading state remains up-to-date with any changes
65to your layout or typography.
66
67### Don't make dedicated skeleton screens
68
69Instead, make components with _built-in_ skeleton states.
70
71This approach is beneficial because:
72
731. It keeps styles in sync.
742. Components should represent all possible states — loading included.
753. It allows for more flexible loading patterns. In the blog post example above,
76 it's possible to have the title load before the body, while having both
77 pieces of content show loading skeletons at the right time.
78
79## Theming
80
81Customize individual skeletons with props, or render a `SkeletonTheme` to style
82all skeletons below it in the React hierarchy:
83
84```tsx
85import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
86
87return (
88 <SkeletonTheme baseColor="#202020" highlightColor="#444">
89 <p>
90 <Skeleton count={3} />
91 </p>
92 </SkeletonTheme>
93);
94```
95
96## Props Reference
97
98### `Skeleton` only
99
100<table>
101 <thead>
102 <tr>
103 <th>Prop</th>
104 <th>Description</th>
105 <th>Default</th>
106 </tr>
107 </thead>
108 <tbody>
109 <tr>
110 <td><code>count?: number</code></td>
111 <td>
112 The number of lines of skeletons to render. If
113 <code>count</code> is a decimal number like 3.5,
114 three full skeletons and one half-width skeleton will be
115 rendered.
116 </td>
117 <td><code>1</code></td>
118 </tr>
119 <tr>
120 <td><code>wrapper?: React.FunctionComponent <br> &lt;PropsWithChildren&lt;unknown&gt;&gt;</code></td>
121 <td>
122 A custom wrapper component that goes around the individual skeleton
123 elements.
124 </td>
125 <td></td>
126 </tr>
127 <tr>
128 <td><code>circle?: boolean</code></td>
129 <td>
130 Makes the skeleton circular by setting <code>border-radius</code> to
131 <code>50%</code>.
132 </td>
133 <td><code>false</code></td>
134 </tr>
135 <tr>
136 <td><code>className?: string</code></td>
137 <td>
138 A custom class name for the individual skeleton elements which is used
139 alongside the default class, <code>react-loading-skeleton</code>.
140 </td>
141 <td></td>
142 </tr>
143 <tr>
144 <td><code>containerClassName?: string</code></td>
145 <td>
146 A custom class name for the <code>&lt;span&gt;</code> that wraps the
147 individual skeleton elements.
148 </td>
149 <td></td>
150 </tr>
151 <tr>
152 <td><code>containerTestId?: string</code></td>
153 <td>
154 A string that is added to the container element as a
155 <code>data-testid</code> attribute. Use it with
156 <code>screen.getByTestId('...')</code> from React Testing Library.
157 </td>
158 <td></td>
159 </tr>
160 <tr>
161 <td><code>style?: React.CSSProperties</code></td>
162 <td>
163 This is an escape hatch for advanced use cases and is not the preferred
164 way to style the skeleton. Props (e.g. <code>width</code>,
165 <code>borderRadius</code>) take priority over this style object.
166 </td>
167 <td></td>
168 </tr>
169 </tbody>
170</table>
171
172### `Skeleton` and `SkeletonTheme`
173
174<table>
175 <thead>
176 <tr>
177 <th>Prop</th>
178 <th>Description</th>
179 <th>Default</th>
180 </tr>
181 </thead>
182 <tbody>
183 <tr>
184 <td><code>baseColor?: string</code></td>
185 <td>The background color of the skeleton.</td>
186 <td><code>#ebebeb</code></td>
187 </tr>
188 <tr>
189 <td><code>highlightColor?: string</code></td>
190 <td>The highlight color in the skeleton animation.</td>
191 <td><code>#f5f5f5</code></td>
192 </tr>
193 <tr>
194 <td><code>width?: string | number</code></td>
195 <td>The width of the skeleton.</td>
196 <td><code>100%</code></td>
197 </tr>
198 <tr>
199 <td><code>height?: string | number</code></td>
200 <td>The height of each skeleton line.</td>
201 <td>The font size</td>
202 </tr>
203 <tr>
204 <td><code>borderRadius?: string | number</code></td>
205 <td>The border radius of the skeleton.</td>
206 <td><code>0.25rem</code></td>
207 </tr>
208 <tr>
209 <td><code>inline?: boolean</code></td>
210 <td>
211 By default, a <code>&lt;br /&gt;</code> is inserted after each skeleton so
212 that each skeleton gets its own line. When <code>inline</code> is true, no
213 line breaks are inserted.
214 </td>
215 <td><code>false</code></td>
216 </tr>
217 <tr>
218 <td><code>duration?: number</code></td>
219 <td>The length of the animation in seconds.</td>
220 <td><code>1.5</code></td>
221 </tr>
222 <tr>
223 <td><code>direction?: 'ltr' | 'rtl'</code></td>
224 <td>
225 The direction of the animation, either left-to-right or right-to-left.
226 </td>
227 <td><code>'ltr'</code></td>
228 </tr>
229 <tr>
230 <td><code>enableAnimation?: boolean</code></td>
231 <td>
232 Whether the animation should play. The skeleton will be a solid color when
233 this is <code>false</code>. You could use this prop to stop the animation
234 if an error occurs.
235 </td>
236 <td><code>true</code></td>
237 </tr>
238 <tr>
239 <td><code>customHighlightBackground?: string</code></td>
240 <td>
241 Allows you to override the <code>background-image</code> property of the highlight element, enabling you to fully customize the gradient. See example below.
242 </td>
243 <td><code>undefined</code></td>
244 </tr>
245 </tbody>
246</table>
247
248## Examples
249
250### Custom Wrapper
251
252There are two ways to wrap a skeleton in a container:
253
254```tsx
255function Box({ children }: PropsWithChildren<unknown>) {
256 return (
257 <div
258 style={{
259 border: '1px solid #ccc',
260 display: 'block',
261 lineHeight: 2,
262 padding: '1rem',
263 marginBottom: '0.5rem',
264 width: 100,
265 }}
266 >
267 {children}
268 </div>
269 );
270}
271
272// Method 1: Use the wrapper prop
273const wrapped1 = <Skeleton wrapper={Box} count={5} />;
274
275// Method 2: Do it "the normal way"
276const wrapped2 = (
277 <Box>
278 <Skeleton />
279 </Box>
280);
281```
282
283### Custom Highlight Background
284
285You may want to make the gradient used in the highlight element narrower or wider. To do this, you can set the `customHighlightBackground` prop. Here's an example of a narrow highlight:
286
287```tsx
288<Skeleton customHighlightBackground="linear-gradient(90deg, var(--base-color) 40%, var(--highlight-color) 50%, var(--base-color) 60%)" />
289```
290
291**If you use this prop, the `baseColor` and `highlightColor` props are ignored,** but you can still reference their corresponding CSS variables as shown in the above example.
292
293![Custom highlight background example](assets/custom-highlight-background.png)
294
295## Troubleshooting
296
297### The skeleton width is 0 when the parent has `display: flex`!
298
299In the example below, the width of the skeleton will be 0:
300
301```tsx
302<div style={{ display: 'flex' }}>
303 <Skeleton />
304</div>
305```
306
307This happens because the skeleton has no intrinsic width. You can fix it by
308applying `flex: 1` to the skeleton container via the `containerClassName` prop.
309
310For example, if you are using Tailwind, your code would look like this:
311
312```tsx
313<div style={{ display: 'flex' }}>
314 <Skeleton containerClassName="flex-1" />
315</div>
316```
317
318### The height of my container is off by a few pixels!
319
320In the example below, the height of the `<div>` will be slightly larger than 30
321even though the `react-loading-skeleton` element is exactly 30px.
322
323```tsx
324<div>
325 <Skeleton height={30} />
326</div>
327```
328
329This is a consequence of how `line-height` works in CSS. If you need the `<div>`
330to be exactly 30px tall, set its `line-height` to 1. [See
331here](https://github.com/dvtng/react-loading-skeleton/issues/23#issuecomment-939231878)
332for more details.
333
334## Contributing
335
336Contributions are welcome! See `CONTRIBUTING.md` to get started.
337
338## Acknowledgements
339
340Our logo is based off an image from [Font
341Awesome](https://fontawesome.com/license/free). Thanks!