formik-form-components 0.2.30 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +326 -123
- package/dist/index.d.ts +182 -332
- package/dist/index.js +1888 -3767
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1874 -3739
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -23
package/README.md
CHANGED
|
@@ -1,41 +1,31 @@
|
|
|
1
1
|
# Formik Form Components
|
|
2
2
|
|
|
3
|
-
A comprehensive collection of reusable, accessible, and customizable form components built with **React**, **
|
|
3
|
+
A comprehensive collection of reusable, accessible, and customizable form components built with **React**, **Tailwind CSS**, and **Formik**. This library helps you build production-ready forms faster while maintaining a clean, modern design with pure HTML5 elements.
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
|
+

|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
9
|
-
## Features
|
|
11
|
+
## ✨ Features
|
|
10
12
|
|
|
11
|
-
- 🚀 **
|
|
12
|
-
- 🎨
|
|
13
|
+
- 🚀 **20+** production-ready form components
|
|
14
|
+
- 🎨 Styled with **Tailwind CSS** for maximum flexibility
|
|
13
15
|
- 🔍 Built-in validation support (Formik + Yup)
|
|
14
16
|
- 📱 Fully responsive and mobile-friendly
|
|
15
|
-
- 🎯 Full TypeScript support
|
|
16
|
-
-
|
|
17
|
-
- 📅
|
|
18
|
-
- ✨ Rich text editor powered by Tiptap
|
|
19
|
-
- 📂 File & image uploads with
|
|
17
|
+
- 🎯 Full **TypeScript** support
|
|
18
|
+
- ♿ Accessibility-first with proper ARIA attributes
|
|
19
|
+
- 📅 Native HTML5 date & time pickers
|
|
20
|
+
- ✨ Rich text editor powered by **Tiptap**
|
|
21
|
+
- 📂 File & image uploads with drag-and-drop
|
|
20
22
|
- 🌍 Internationalization (i18n) ready
|
|
23
|
+
- 🎭 No dependencies on UI frameworks (MUI, etc.)
|
|
24
|
+
- 🔧 Fully customizable with Tailwind classes
|
|
21
25
|
|
|
22
26
|
---
|
|
23
27
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
- [Installation](#installation)
|
|
27
|
-
- [Peer Dependencies](#peer-dependencies)
|
|
28
|
-
- [Getting Started](#getting-started)
|
|
29
|
-
- [Available Components](#available-components)
|
|
30
|
-
- [Component Examples](#component-examples)
|
|
31
|
-
- [Theming](#theming)
|
|
32
|
-
- [TypeScript Support](#typescript-support)
|
|
33
|
-
- [Contributing](#contributing)
|
|
34
|
-
- [License](#license)
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Installation
|
|
28
|
+
## 📦 Installation
|
|
39
29
|
|
|
40
30
|
```bash
|
|
41
31
|
# npm
|
|
@@ -43,68 +33,112 @@ npm install formik-form-components
|
|
|
43
33
|
|
|
44
34
|
# yarn
|
|
45
35
|
yarn add formik-form-components
|
|
36
|
+
|
|
37
|
+
# pnpm
|
|
38
|
+
pnpm add formik-form-components
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Peer Dependencies
|
|
42
|
+
|
|
43
|
+
Make sure you have the required peer dependencies installed:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install react react-dom formik tailwindcss
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
---
|
|
49
50
|
|
|
50
|
-
## Getting Started
|
|
51
|
+
## 🚀 Getting Started
|
|
51
52
|
|
|
52
|
-
### 1.
|
|
53
|
+
### 1. Configure Tailwind CSS
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
|
55
|
+
If you haven't already, set up Tailwind CSS in your project:
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
```bash
|
|
58
|
+
npx tailwindcss init -p
|
|
59
|
+
```
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
Update your `tailwind.config.js` to include the package's components:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
/** @type {import('tailwindcss').Config} */
|
|
65
|
+
module.exports = {
|
|
66
|
+
content: [
|
|
67
|
+
"./src/**/*.{js,jsx,ts,tsx}",
|
|
68
|
+
"./node_modules/formik-form-components/dist/**/*.{js,mjs}",
|
|
69
|
+
],
|
|
70
|
+
theme: {
|
|
71
|
+
extend: {
|
|
72
|
+
colors: {
|
|
73
|
+
primary: {
|
|
74
|
+
50: '#e3f2fd',
|
|
75
|
+
100: '#bbdefb',
|
|
76
|
+
200: '#90caf9',
|
|
77
|
+
300: '#64b5f6',
|
|
78
|
+
400: '#42a5f5',
|
|
79
|
+
500: '#2196f3',
|
|
80
|
+
600: '#1e88e5',
|
|
81
|
+
700: '#1976d2',
|
|
82
|
+
800: '#1565c0',
|
|
83
|
+
900: '#0d47a1',
|
|
84
|
+
},
|
|
85
|
+
error: {
|
|
86
|
+
50: '#ffebee',
|
|
87
|
+
100: '#ffcdd2',
|
|
88
|
+
200: '#ef9a9a',
|
|
89
|
+
300: '#e57373',
|
|
90
|
+
400: '#ef5350',
|
|
91
|
+
500: '#f44336',
|
|
92
|
+
600: '#e53935',
|
|
93
|
+
700: '#d32f2f',
|
|
94
|
+
800: '#c62828',
|
|
95
|
+
900: '#b71c1c',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
plugins: [],
|
|
65
101
|
}
|
|
66
102
|
```
|
|
67
103
|
|
|
68
|
-
|
|
104
|
+
### 2. Import Tailwind CSS
|
|
69
105
|
|
|
70
|
-
|
|
106
|
+
In your main CSS file (e.g., `src/index.css` or `src/App.css`):
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
@tailwind base;
|
|
110
|
+
@tailwind components;
|
|
111
|
+
@tailwind utilities;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Basic Form Example
|
|
71
115
|
|
|
72
116
|
```tsx
|
|
73
117
|
import { Formik, Form } from 'formik';
|
|
74
118
|
import * as Yup from 'yup';
|
|
75
|
-
import { Button, Box } from '@mui/material';
|
|
76
119
|
import {
|
|
77
120
|
AppInputField,
|
|
78
121
|
AppCheckBox,
|
|
79
122
|
AppDatePicker,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
AppMultiSelector,
|
|
123
|
+
AppTextArea,
|
|
124
|
+
AppSelectInput,
|
|
125
|
+
SubmitButton,
|
|
84
126
|
} from 'formik-form-components';
|
|
85
127
|
|
|
86
128
|
const validationSchema = Yup.object({
|
|
87
129
|
name: Yup.string().required('Name is required'),
|
|
88
130
|
email: Yup.string().email('Invalid email').required('Email is required'),
|
|
89
|
-
|
|
131
|
+
birthDate: Yup.date().required('Birth date is required'),
|
|
132
|
+
country: Yup.string().required('Country is required'),
|
|
90
133
|
bio: Yup.string().required('Bio is required'),
|
|
91
|
-
rating: Yup.number().required('Rating is required'),
|
|
92
|
-
gender: Yup.string().required('Gender is required'),
|
|
93
|
-
interests: Yup.array().min(1, 'Select at least one interest'),
|
|
94
134
|
terms: Yup.boolean().oneOf([true], 'You must accept the terms'),
|
|
95
135
|
});
|
|
96
136
|
|
|
97
|
-
const
|
|
98
|
-
{
|
|
99
|
-
{
|
|
100
|
-
{
|
|
101
|
-
{
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
const genderOptions = [
|
|
105
|
-
{ value: 'male', label: 'Male' },
|
|
106
|
-
{ value: 'female', label: 'Female' },
|
|
107
|
-
{ value: 'other', label: 'Other' },
|
|
137
|
+
const countryOptions = [
|
|
138
|
+
{ label: 'United States', value: 'us' },
|
|
139
|
+
{ label: 'Canada', value: 'ca' },
|
|
140
|
+
{ label: 'United Kingdom', value: 'uk' },
|
|
141
|
+
{ label: 'Australia', value: 'au' },
|
|
108
142
|
];
|
|
109
143
|
|
|
110
144
|
export default function ExampleForm() {
|
|
@@ -113,34 +147,69 @@ export default function ExampleForm() {
|
|
|
113
147
|
initialValues={{
|
|
114
148
|
name: '',
|
|
115
149
|
email: '',
|
|
116
|
-
|
|
150
|
+
birthDate: null,
|
|
151
|
+
country: '',
|
|
117
152
|
bio: '',
|
|
118
|
-
rating: 0,
|
|
119
|
-
gender: '',
|
|
120
|
-
interests: [],
|
|
121
153
|
terms: false,
|
|
122
154
|
}}
|
|
123
155
|
validationSchema={validationSchema}
|
|
124
156
|
onSubmit={(values) => console.log(values)}
|
|
125
157
|
>
|
|
126
158
|
{({ isSubmitting }) => (
|
|
127
|
-
<Form>
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
159
|
+
<Form className="max-w-2xl mx-auto p-6 space-y-4">
|
|
160
|
+
<h1 className="text-2xl font-bold mb-6">User Registration</h1>
|
|
161
|
+
|
|
162
|
+
<AppInputField
|
|
163
|
+
name="name"
|
|
164
|
+
label="Full Name"
|
|
165
|
+
required
|
|
166
|
+
/>
|
|
167
|
+
|
|
168
|
+
<AppInputField
|
|
169
|
+
name="email"
|
|
170
|
+
label="Email Address"
|
|
171
|
+
type="email"
|
|
172
|
+
required
|
|
173
|
+
/>
|
|
174
|
+
|
|
175
|
+
<AppDatePicker
|
|
176
|
+
name="birthDate"
|
|
177
|
+
label="Date of Birth"
|
|
178
|
+
required
|
|
179
|
+
/>
|
|
180
|
+
|
|
181
|
+
<AppSelectInput
|
|
182
|
+
name="country"
|
|
183
|
+
label="Country"
|
|
184
|
+
options={countryOptions}
|
|
185
|
+
placeholder="Select a country"
|
|
186
|
+
required
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
<AppTextArea
|
|
190
|
+
name="bio"
|
|
191
|
+
label="Bio"
|
|
192
|
+
rows={4}
|
|
193
|
+
maxLength={500}
|
|
194
|
+
showCount
|
|
195
|
+
required
|
|
196
|
+
/>
|
|
197
|
+
|
|
198
|
+
<AppCheckBox
|
|
199
|
+
name="terms"
|
|
200
|
+
option={[{
|
|
201
|
+
name: 'terms',
|
|
202
|
+
label: 'I agree to the terms and conditions',
|
|
203
|
+
value: true
|
|
204
|
+
}]}
|
|
205
|
+
/>
|
|
206
|
+
|
|
207
|
+
<SubmitButton
|
|
208
|
+
loading={isSubmitting}
|
|
209
|
+
fullWidth
|
|
210
|
+
>
|
|
211
|
+
Submit
|
|
212
|
+
</SubmitButton>
|
|
144
213
|
</Form>
|
|
145
214
|
)}
|
|
146
215
|
</Formik>
|
|
@@ -150,94 +219,228 @@ export default function ExampleForm() {
|
|
|
150
219
|
|
|
151
220
|
---
|
|
152
221
|
|
|
153
|
-
## Available Components
|
|
222
|
+
## 📚 Available Components
|
|
154
223
|
|
|
155
224
|
### Form Inputs
|
|
156
225
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
226
|
+
- **`AppInputField`** - Text input with validation and password toggle
|
|
227
|
+
- **`AppTextArea`** - Multi-line text input with character counter
|
|
228
|
+
- **`AppCheckBox`** - Checkbox input (single or multiple)
|
|
229
|
+
- **`AppSwitch`** / **`AppSwitchInput`** - Toggle switch component
|
|
230
|
+
- **`AppRadioGroup`** - Radio button group
|
|
231
|
+
- **`AppRating`** - Star rating component
|
|
232
|
+
- **`AppPhoneNoInput`** - International phone number input
|
|
163
233
|
|
|
164
234
|
### Selection Components
|
|
165
235
|
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
236
|
+
- **`AppSelectInput`** - Native HTML select dropdown
|
|
237
|
+
- **`AppAutoComplete`** - Autocomplete with tags
|
|
238
|
+
- **`AppAutoCompleter`** - Advanced autocomplete with search
|
|
239
|
+
- **`AppMultiSelector`** - Multi-select with checkboxes
|
|
240
|
+
- **`AppTagsCreator`** - Tag input with suggestions
|
|
170
241
|
|
|
171
242
|
### Date & Time Pickers
|
|
172
243
|
|
|
173
|
-
-
|
|
174
|
-
-
|
|
175
|
-
- `AppDateAndTimePicker`
|
|
176
|
-
- `AppDateTimePicker`
|
|
244
|
+
- **`AppDatePicker`** - Native HTML5 date picker
|
|
245
|
+
- **`AppDateAndTimePicker`** - Native HTML5 datetime-local picker
|
|
177
246
|
|
|
178
247
|
### File Handling
|
|
179
248
|
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
|
|
183
|
-
|
|
249
|
+
- **`AppUploadFile`** - Drag-and-drop file upload with preview
|
|
250
|
+
- **`AppSimpleUploadFile`** - Simple file upload button
|
|
251
|
+
|
|
252
|
+
### Rich Text
|
|
253
|
+
|
|
254
|
+
- **`AppRichTextEditor`** - Rich text editor powered by Tiptap
|
|
255
|
+
|
|
256
|
+
### Other
|
|
257
|
+
|
|
258
|
+
- **`SubmitButton`** - Submit button with loading state
|
|
259
|
+
- **`Iconify`** - Icon component (optional, uses @iconify/react)
|
|
184
260
|
|
|
185
261
|
---
|
|
186
262
|
|
|
187
|
-
##
|
|
263
|
+
## 🎨 Customization
|
|
188
264
|
|
|
189
|
-
All components
|
|
265
|
+
All components accept standard Tailwind CSS classes for customization:
|
|
190
266
|
|
|
191
267
|
```tsx
|
|
192
|
-
|
|
268
|
+
<AppInputField
|
|
269
|
+
name="email"
|
|
270
|
+
label="Email"
|
|
271
|
+
className="border-2 border-blue-500"
|
|
272
|
+
labelClassName="text-lg font-bold"
|
|
273
|
+
containerClassName="mb-6"
|
|
274
|
+
/>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Custom Theme Colors
|
|
193
278
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
279
|
+
You can customize the primary and error colors in your `tailwind.config.js` to match your brand:
|
|
280
|
+
|
|
281
|
+
```js
|
|
282
|
+
theme: {
|
|
283
|
+
extend: {
|
|
284
|
+
colors: {
|
|
285
|
+
primary: {
|
|
286
|
+
500: '#your-brand-color',
|
|
287
|
+
600: '#your-brand-color-dark',
|
|
288
|
+
// ... other shades
|
|
289
|
+
},
|
|
290
|
+
},
|
|
198
291
|
},
|
|
199
|
-
}
|
|
292
|
+
},
|
|
200
293
|
```
|
|
201
294
|
|
|
202
|
-
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## 🔧 Component Props
|
|
298
|
+
|
|
299
|
+
### Common Props (Available on Most Components)
|
|
203
300
|
|
|
204
301
|
```tsx
|
|
205
|
-
|
|
206
|
-
|
|
302
|
+
interface CommonProps {
|
|
303
|
+
name: string; // Required: Field name for Formik
|
|
304
|
+
label?: string; // Label text
|
|
305
|
+
required?: boolean; // Show required indicator
|
|
306
|
+
disabled?: boolean; // Disable the field
|
|
307
|
+
helperText?: string; // Helper text below input
|
|
308
|
+
className?: string; // Custom classes for input
|
|
309
|
+
labelClassName?: string; // Custom classes for label
|
|
310
|
+
errorClassName?: string; // Custom classes for error text
|
|
311
|
+
containerClassName?: string; // Custom classes for container
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### AppInputField Specific Props
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
interface AppInputFieldProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
319
|
+
name: string;
|
|
320
|
+
label?: ReactNode;
|
|
321
|
+
required?: boolean;
|
|
322
|
+
helperText?: string;
|
|
323
|
+
// ... plus all HTML input attributes
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## 📖 Advanced Examples
|
|
330
|
+
|
|
331
|
+
### Custom Validation Messages
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
const schema = Yup.object({
|
|
335
|
+
password: Yup.string()
|
|
336
|
+
.min(8, 'Password must be at least 8 characters')
|
|
337
|
+
.matches(/[A-Z]/, 'Must contain at least one uppercase letter')
|
|
338
|
+
.required('Password is required'),
|
|
207
339
|
});
|
|
208
340
|
```
|
|
209
341
|
|
|
342
|
+
### Multi-Step Form
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
const [step, setStep] = useState(1);
|
|
346
|
+
|
|
347
|
+
return (
|
|
348
|
+
<Formik
|
|
349
|
+
initialValues={initialValues}
|
|
350
|
+
validationSchema={getValidationSchema(step)}
|
|
351
|
+
onSubmit={(values) => {
|
|
352
|
+
if (step < 3) {
|
|
353
|
+
setStep(step + 1);
|
|
354
|
+
} else {
|
|
355
|
+
// Submit final form
|
|
356
|
+
}
|
|
357
|
+
}}
|
|
358
|
+
>
|
|
359
|
+
{/* Render different fields based on step */}
|
|
360
|
+
</Formik>
|
|
361
|
+
);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### File Upload with Preview
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
<AppUploadFile
|
|
368
|
+
name="avatar"
|
|
369
|
+
label="Upload Profile Picture"
|
|
370
|
+
accept={{ 'image/*': ['.png', '.jpg', '.jpeg'] }}
|
|
371
|
+
maxSize={2 * 1024 * 1024} // 2MB
|
|
372
|
+
maxFiles={1}
|
|
373
|
+
/>
|
|
374
|
+
```
|
|
375
|
+
|
|
210
376
|
---
|
|
211
377
|
|
|
212
|
-
##
|
|
378
|
+
## 🌐 Internationalization
|
|
213
379
|
|
|
214
|
-
|
|
380
|
+
Components support i18n through React-i18next:
|
|
215
381
|
|
|
216
382
|
```tsx
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
};
|
|
383
|
+
import { useTranslation } from 'react-i18next';
|
|
384
|
+
|
|
385
|
+
function MyForm() {
|
|
386
|
+
const { t } = useTranslation();
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<AppInputField
|
|
390
|
+
name="name"
|
|
391
|
+
label={t('form.name')}
|
|
392
|
+
placeholder={t('form.namePlaceholder')}
|
|
393
|
+
/>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
221
396
|
```
|
|
222
397
|
|
|
223
398
|
---
|
|
224
399
|
|
|
225
|
-
##
|
|
400
|
+
## ♿ Accessibility
|
|
401
|
+
|
|
402
|
+
All components are built with accessibility in mind:
|
|
403
|
+
|
|
404
|
+
- Proper ARIA labels and descriptions
|
|
405
|
+
- Keyboard navigation support
|
|
406
|
+
- Screen reader friendly
|
|
407
|
+
- Focus management
|
|
408
|
+
- Error announcements
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 🤝 Contributing
|
|
413
|
+
|
|
414
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
226
415
|
|
|
227
416
|
1. Fork the repository
|
|
228
|
-
2. Create a feature branch
|
|
229
|
-
3. Commit your changes
|
|
230
|
-
4.
|
|
417
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
418
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
419
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
420
|
+
5. Open a Pull Request
|
|
231
421
|
|
|
232
422
|
---
|
|
233
423
|
|
|
234
|
-
## License
|
|
424
|
+
## 📄 License
|
|
235
425
|
|
|
236
|
-
MIT © tkturners
|
|
426
|
+
MIT © [tkturners](https://github.com/tkturners)
|
|
237
427
|
|
|
238
428
|
---
|
|
239
429
|
|
|
240
|
-
## Support
|
|
430
|
+
## 🆘 Support
|
|
241
431
|
|
|
242
432
|
If you find a bug or have a feature request, please open an issue on GitHub:
|
|
243
|
-
https://github.com/tkturners/formik-form-components/issues
|
|
433
|
+
[https://github.com/tkturners/formik-form-components/issues](https://github.com/tkturners/formik-form-components/issues)
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## 🙏 Acknowledgments
|
|
438
|
+
|
|
439
|
+
- Built with [Formik](https://formik.org/)
|
|
440
|
+
- Styled with [Tailwind CSS](https://tailwindcss.com/)
|
|
441
|
+
- Rich text editing powered by [Tiptap](https://tiptap.dev/)
|
|
442
|
+
- Icons from [@iconify/react](https://iconify.design/)
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
**Happy Coding! 🎉**
|