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> • -->
|
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 |
|
16 | Learn about the [changes in version
|
17 | 3](https://github.com/dvtng/react-loading-skeleton/releases/tag/v3.0.0), or view
|
18 | the [v2
|
19 | documentation](https://github.com/dvtng/react-loading-skeleton/tree/v2#readme).
|
20 |
|
21 | ## Basic Usage
|
22 |
|
23 | Install via one of:
|
24 |
|
25 | ```bash
|
26 | yarn add react-loading-skeleton
|
27 | npm install react-loading-skeleton
|
28 | ```
|
29 |
|
30 | ```tsx
|
31 | import Skeleton from 'react-loading-skeleton'
|
32 | import '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 |
|
42 | The `Skeleton` component should be used directly in your components in place of
|
43 | content that is loading. While other libraries require you to meticulously craft
|
44 | a skeleton screen that matches the font size, line height, and margins of your
|
45 | content, the `Skeleton` component is automatically sized to the correct
|
46 | dimensions.
|
47 |
|
48 | For example:
|
49 |
|
50 | ```tsx
|
51 | function 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
|
62 | further configuration.
|
63 |
|
64 | This ensures the loading state remains up-to-date with any changes
|
65 | to your layout or typography.
|
66 |
|
67 | ### Don't make dedicated skeleton screens
|
68 |
|
69 | Instead, make components with _built-in_ skeleton states.
|
70 |
|
71 | This approach is beneficial because:
|
72 |
|
73 | 1. It keeps styles in sync.
|
74 | 2. Components should represent all possible states — loading included.
|
75 | 3. 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 |
|
81 | Customize individual skeletons with props, or render a `SkeletonTheme` to style
|
82 | all skeletons below it in the React hierarchy:
|
83 |
|
84 | ```tsx
|
85 | import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
86 |
|
87 | return (
|
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> <PropsWithChildren<unknown>></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><span></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><br /></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 |
|
252 | There are two ways to wrap a skeleton in a container:
|
253 |
|
254 | ```tsx
|
255 | function 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
|
273 | const wrapped1 = <Skeleton wrapper={Box} count={5} />;
|
274 |
|
275 | // Method 2: Do it "the normal way"
|
276 | const wrapped2 = (
|
277 | <Box>
|
278 | <Skeleton />
|
279 | </Box>
|
280 | );
|
281 | ```
|
282 |
|
283 | ### Custom Highlight Background
|
284 |
|
285 | You 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 |
|
299 | In 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 |
|
307 | This happens because the skeleton has no intrinsic width. You can fix it by
|
308 | applying `flex: 1` to the skeleton container via the `containerClassName` prop.
|
309 |
|
310 | For 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 |
|
320 | In the example below, the height of the `<div>` will be slightly larger than 30
|
321 | even though the `react-loading-skeleton` element is exactly 30px.
|
322 |
|
323 | ```tsx
|
324 | <div>
|
325 | <Skeleton height={30} />
|
326 | </div>
|
327 | ```
|
328 |
|
329 | This is a consequence of how `line-height` works in CSS. If you need the `<div>`
|
330 | to be exactly 30px tall, set its `line-height` to 1. [See
|
331 | here](https://github.com/dvtng/react-loading-skeleton/issues/23#issuecomment-939231878)
|
332 | for more details.
|
333 |
|
334 | ## Contributing
|
335 |
|
336 | Contributions are welcome! See `CONTRIBUTING.md` to get started.
|
337 |
|
338 | ## Acknowledgements
|
339 |
|
340 | Our logo is based off an image from [Font
|
341 | Awesome](https://fontawesome.com/license/free). Thanks!
|