react-multiselect-ui 2.0.0 → 2.0.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 CHANGED
@@ -1,73 +1,704 @@
1
- # React + TypeScript + Vite
1
+ # react-multiselect-ui
2
2
 
3
- This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
3
+ A ShadCN-style, fully accessible **Multi Select** component for React built with Tailwind CSS, Radix UI, and cmdk.
4
4
 
5
- Currently, two official plugins are available:
5
+ [![npm version](https://img.shields.io/npm/v/react-multiselect-ui)](https://www.npmjs.com/package/react-multiselect-ui)
6
+ [![npm downloads](https://img.shields.io/npm/dm/react-multiselect-ui)](https://www.npmjs.com/package/react-multiselect-ui)
7
+ [![license](https://img.shields.io/npm/l/react-multiselect-ui)](./LICENSE)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-ready-blue)](https://www.typescriptlang.org/)
6
9
 
7
- - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
8
- - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
10
+ ---
9
11
 
10
- ## React Compiler
12
+ ## Features
11
13
 
12
- The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
14
+ - Select multiple options with badge display
15
+ - ✅ Searchable dropdown powered by `cmdk`
16
+ - ✅ Keyboard navigation (Arrow keys, Enter, Escape)
17
+ - ✅ Full WAI-ARIA accessibility
18
+ - ✅ Dark mode support out of the box
19
+ - ✅ Max selection limit (`maxCount`)
20
+ - ✅ Clear all / remove individual selections
21
+ - ✅ TypeScript — fully typed props and exports
22
+ - ✅ ShadCN-compatible Tailwind styling
23
+ - ✅ No lucide-react dependency — uses inline SVGs
24
+ - ✅ Supports React 17, 18, and 19
25
+ - ✅ Supports Tailwind CSS v3 and v4
13
26
 
14
- ## Expanding the ESLint configuration
27
+ ---
15
28
 
16
- If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
29
+ ## Compatibility
17
30
 
18
- ```js
19
- export default defineConfig([
20
- globalIgnores(['dist']),
21
- {
22
- files: ['**/*.{ts,tsx}'],
23
- extends: [
24
- // Other configs...
25
-
26
- // Remove tseslint.configs.recommended and replace with this
27
- tseslint.configs.recommendedTypeChecked,
28
- // Alternatively, use this for stricter rules
29
- tseslint.configs.strictTypeChecked,
30
- // Optionally, add this for stylistic rules
31
- tseslint.configs.stylisticTypeChecked,
32
-
33
- // Other configs...
34
- ],
35
- languageOptions: {
36
- parserOptions: {
37
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
38
- tsconfigRootDir: import.meta.dirname,
39
- },
40
- // other options...
41
- },
42
- },
43
- ])
31
+ | Tool | Supported Versions |
32
+ |---|---|
33
+ | React | 17, 18, 19 |
34
+ | Tailwind CSS | v3, v4 |
35
+ | TypeScript | 4.x, 5.x |
36
+ | Node.js | 18+ |
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ # npm
44
+ npm install react-multiselect-ui
45
+
46
+ # yarn
47
+ yarn add react-multiselect-ui
48
+
49
+ # pnpm
50
+ pnpm add react-multiselect-ui
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Peer Dependencies
56
+
57
+ Make sure these are already in your project:
58
+
59
+ ```bash
60
+ npm install react react-dom
44
61
  ```
45
62
 
46
- You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
63
+ ---
64
+
65
+ ## Tailwind Setup
66
+
67
+ > This step is required for the component to be styled correctly. Skip it and the component will render unstyled.
68
+
69
+ ### Tailwind v4
70
+
71
+ Add the `@source` directive so Tailwind scans the component's class names:
72
+
73
+ ```css
74
+ /* src/index.css or src/globals.css */
75
+ @import "tailwindcss";
76
+
77
+ /* Required — tells Tailwind v4 to scan the package */
78
+ @source "../../node_modules/react-multiselect-ui/dist";
79
+ ```
80
+
81
+ > Adjust the relative path based on where your CSS file lives:
82
+ > - CSS at `src/index.css` → use `../../node_modules/...`
83
+ > - CSS at root `styles/globals.css` → use `../node_modules/...`
84
+ > - CSS at root `index.css` → use `./node_modules/...`
85
+
86
+ ### Tailwind v3
87
+
88
+ Add the dist path to the `content` array in `tailwind.config.js`:
47
89
 
48
90
  ```js
49
- // eslint.config.js
50
- import reactX from 'eslint-plugin-react-x'
51
- import reactDom from 'eslint-plugin-react-dom'
52
-
53
- export default defineConfig([
54
- globalIgnores(['dist']),
55
- {
56
- files: ['**/*.{ts,tsx}'],
57
- extends: [
58
- // Other configs...
59
- // Enable lint rules for React
60
- reactX.configs['recommended-typescript'],
61
- // Enable lint rules for React DOM
62
- reactDom.configs.recommended,
63
- ],
64
- languageOptions: {
65
- parserOptions: {
66
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
67
- tsconfigRootDir: import.meta.dirname,
68
- },
69
- // other options...
70
- },
91
+ // tailwind.config.js
92
+ module.exports = {
93
+ content: [
94
+ "./src/**/*.{js,ts,jsx,tsx}",
95
+ // Required — tells Tailwind v3 to scan the package
96
+ "./node_modules/react-multiselect-ui/dist/**/*.{js,mjs}",
97
+ ],
98
+ theme: {
99
+ extend: {},
71
100
  },
72
- ])
101
+ plugins: [],
102
+ };
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Quick Start
108
+
109
+ ```tsx
110
+ import { useState } from "react";
111
+ import { MultiSelect } from "react-multiselect-ui";
112
+
113
+ const options = [
114
+ { value: "react", label: "React" },
115
+ { value: "vue", label: "Vue" },
116
+ { value: "svelte", label: "Svelte" },
117
+ { value: "angular", label: "Angular" },
118
+ ];
119
+
120
+ export default function App() {
121
+ const [selected, setSelected] = useState<string[]>([]);
122
+
123
+ return (
124
+ <MultiSelect
125
+ options={options}
126
+ value={selected}
127
+ onValueChange={setSelected}
128
+ placeholder="Select frameworks..."
129
+ />
130
+ );
131
+ }
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Examples
137
+
138
+ ### 1. Basic Usage
139
+
140
+ ```tsx
141
+ import { useState } from "react";
142
+ import { MultiSelect } from "react-multiselect-ui";
143
+
144
+ const FRUITS = [
145
+ { value: "apple", label: "Apple" },
146
+ { value: "banana", label: "Banana" },
147
+ { value: "cherry", label: "Cherry" },
148
+ { value: "mango", label: "Mango" },
149
+ { value: "orange", label: "Orange" },
150
+ ];
151
+
152
+ export function BasicExample() {
153
+ const [selected, setSelected] = useState<string[]>([]);
154
+
155
+ return (
156
+ <div className="w-80">
157
+ <MultiSelect
158
+ options={FRUITS}
159
+ value={selected}
160
+ onValueChange={setSelected}
161
+ placeholder="Pick some fruits..."
162
+ />
163
+ <p className="mt-2 text-sm text-gray-500">
164
+ Selected: {selected.length === 0 ? "none" : selected.join(", ")}
165
+ </p>
166
+ </div>
167
+ );
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ### 2. Pre-selected Values
174
+
175
+ Initialize `useState` with values to show defaults on first render:
176
+
177
+ ```tsx
178
+ export function PreselectedExample() {
179
+ const [languages, setLanguages] = useState<string[]>(["en", "es"]);
180
+
181
+ return (
182
+ <MultiSelect
183
+ options={[
184
+ { value: "en", label: "English" },
185
+ { value: "es", label: "Spanish" },
186
+ { value: "fr", label: "French" },
187
+ { value: "de", label: "German" },
188
+ { value: "zh", label: "Chinese" },
189
+ ]}
190
+ value={languages}
191
+ onValueChange={setLanguages}
192
+ placeholder="Select languages..."
193
+ />
194
+ );
195
+ }
196
+ ```
197
+
198
+ ---
199
+
200
+ ### 3. Max Selection Limit
201
+
202
+ Use `maxCount` to cap how many items can be selected. Options automatically disable once the limit is reached:
203
+
204
+ ```tsx
205
+ export function MaxSelectExample() {
206
+ const [toppings, setToppings] = useState<string[]>([]);
207
+
208
+ return (
209
+ <div className="w-80">
210
+ <MultiSelect
211
+ options={[
212
+ { value: "cheese", label: "Extra Cheese" },
213
+ { value: "mushrooms", label: "Mushrooms" },
214
+ { value: "peppers", label: "Bell Peppers" },
215
+ { value: "onions", label: "Onions" },
216
+ { value: "olives", label: "Olives" },
217
+ ]}
218
+ value={toppings}
219
+ onValueChange={setToppings}
220
+ placeholder="Select toppings..."
221
+ maxCount={3}
222
+ />
223
+ {toppings.length === 3 && (
224
+ <p className="mt-1 text-xs text-amber-600">
225
+ Maximum 3 toppings reached!
226
+ </p>
227
+ )}
228
+ </div>
229
+ );
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ### 4. Disabled Component
236
+
237
+ Disable the entire component conditionally:
238
+
239
+ ```tsx
240
+ export function DisabledExample() {
241
+ const [isLocked, setIsLocked] = useState(true);
242
+ const [roles, setRoles] = useState<string[]>(["viewer"]);
243
+
244
+ return (
245
+ <div className="space-y-2 w-80">
246
+ <MultiSelect
247
+ options={[
248
+ { value: "admin", label: "Admin" },
249
+ { value: "editor", label: "Editor" },
250
+ { value: "viewer", label: "Viewer" },
251
+ { value: "guest", label: "Guest" },
252
+ ]}
253
+ value={roles}
254
+ onValueChange={setRoles}
255
+ placeholder="Select roles..."
256
+ disabled={isLocked}
257
+ />
258
+ <button
259
+ onClick={() => setIsLocked((v) => !v)}
260
+ className="text-sm text-blue-600 underline"
261
+ >
262
+ {isLocked ? "Unlock" : "Lock"} selector
263
+ </button>
264
+ </div>
265
+ );
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ### 5. Disabled Individual Options
272
+
273
+ Mark specific options as unselectable while keeping others available:
274
+
275
+ ```tsx
276
+ const PLANS = [
277
+ { value: "free", label: "Free Tier" },
278
+ { value: "pro", label: "Pro" },
279
+ { value: "team", label: "Team" },
280
+ // This option cannot be selected
281
+ { value: "enterprise", label: "Enterprise — contact sales", disabled: true },
282
+ ];
283
+
284
+ export function DisabledOptionsExample() {
285
+ const [plan, setPlan] = useState<string[]>([]);
286
+
287
+ return (
288
+ <MultiSelect
289
+ options={PLANS}
290
+ value={plan}
291
+ onValueChange={setPlan}
292
+ placeholder="Select a plan..."
293
+ />
294
+ );
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ### 6. Inside a Form with Reset
301
+
302
+ ```tsx
303
+ export function FormExample() {
304
+ const [skills, setSkills] = useState<string[]>([]);
305
+ const [submitted, setSubmitted] = useState<string[]>([]);
306
+
307
+ const handleSubmit = (e: React.FormEvent) => {
308
+ e.preventDefault();
309
+ setSubmitted([...skills]);
310
+ setSkills([]); // Reset after submit
311
+ };
312
+
313
+ return (
314
+ <form onSubmit={handleSubmit} className="space-y-3 w-80">
315
+ <MultiSelect
316
+ options={[
317
+ { value: "typescript", label: "TypeScript" },
318
+ { value: "react", label: "React" },
319
+ { value: "node", label: "Node.js" },
320
+ { value: "python", label: "Python" },
321
+ { value: "go", label: "Go" },
322
+ { value: "rust", label: "Rust" },
323
+ ]}
324
+ value={skills}
325
+ onValueChange={setSkills}
326
+ placeholder="Select your skills..."
327
+ />
328
+ <button
329
+ type="submit"
330
+ disabled={skills.length === 0}
331
+ className="w-full rounded-md bg-zinc-900 px-4 py-2 text-sm
332
+ font-medium text-white disabled:opacity-50"
333
+ >
334
+ Submit
335
+ </button>
336
+ {submitted.length > 0 && (
337
+ <p className="text-sm text-green-700">
338
+ Submitted: {submitted.join(", ")}
339
+ </p>
340
+ )}
341
+ </form>
342
+ );
343
+ }
344
+ ```
345
+
346
+ ---
347
+
348
+ ### 7. Without Clear Button
349
+
350
+ Hide the "Clear all" control so users can only deselect via individual badge X buttons:
351
+
352
+ ```tsx
353
+ <MultiSelect
354
+ options={options}
355
+ value={selected}
356
+ onValueChange={setSelected}
357
+ placeholder="Add labels..."
358
+ clearable={false}
359
+ />
360
+ ```
361
+
362
+ ---
363
+
364
+ ### 8. Custom Search and Empty Text
365
+
366
+ ```tsx
367
+ <MultiSelect
368
+ options={options}
369
+ value={selected}
370
+ onValueChange={setSelected}
371
+ placeholder="Choose team members..."
372
+ searchPlaceholder="Type a name to search..."
373
+ emptyText="No team members match your search."
374
+ />
375
+ ```
376
+
377
+ ---
378
+
379
+ ### 9. Custom Styling
380
+
381
+ Use `className` to style the trigger button and `contentClassName` for the dropdown panel:
382
+
383
+ ```tsx
384
+ <MultiSelect
385
+ options={options}
386
+ value={selected}
387
+ onValueChange={setSelected}
388
+ placeholder="Pick colors..."
389
+ className="border-violet-300 focus-visible:ring-violet-500"
390
+ contentClassName="border-violet-200"
391
+ />
392
+ ```
393
+
394
+ ---
395
+
396
+ ### 10. Async / API-loaded Options
397
+
398
+ ```tsx
399
+ import { useState, useEffect } from "react";
400
+ import { MultiSelect } from "react-multiselect-ui";
401
+ import type { MultiSelectOption } from "react-multiselect-ui";
402
+
403
+ export function AsyncExample() {
404
+ const [options, setOptions] = useState<MultiSelectOption[]>([]);
405
+ const [selected, setSelected] = useState<string[]>([]);
406
+ const [loading, setLoading] = useState(true);
407
+
408
+ useEffect(() => {
409
+ fetch("/api/users")
410
+ .then((res) => res.json())
411
+ .then((data) => {
412
+ setOptions(
413
+ data.map((u: { id: string; name: string }) => ({
414
+ value: u.id,
415
+ label: u.name,
416
+ }))
417
+ );
418
+ setLoading(false);
419
+ });
420
+ }, []);
421
+
422
+ if (loading) {
423
+ return (
424
+ <div className="h-9 w-full animate-pulse rounded-md bg-zinc-100" />
425
+ );
426
+ }
427
+
428
+ return (
429
+ <MultiSelect
430
+ options={options}
431
+ value={selected}
432
+ onValueChange={setSelected}
433
+ placeholder="Assign team members..."
434
+ searchPlaceholder="Search by name..."
435
+ />
436
+ );
437
+ }
438
+ ```
439
+
440
+ ---
441
+
442
+ ### 11. Accessible with ARIA Label
443
+
444
+ ```tsx
445
+ <MultiSelect
446
+ options={options}
447
+ value={selected}
448
+ onValueChange={setSelected}
449
+ placeholder="Filter by department..."
450
+ aria-label="Filter results by department"
451
+ />
452
+ ```
453
+
454
+ ---
455
+
456
+ ### 12. Controlled Reset from Parent
457
+
458
+ ```tsx
459
+ export function ParentControlExample() {
460
+ const [selected, setSelected] = useState<string[]>(["react", "typescript"]);
461
+
462
+ return (
463
+ <div className="space-y-3 w-80">
464
+ <MultiSelect
465
+ options={options}
466
+ value={selected}
467
+ onValueChange={setSelected}
468
+ placeholder="Select technologies..."
469
+ />
470
+ <div className="flex gap-2">
471
+ <button onClick={() => setSelected([])}>
472
+ Clear All
473
+ </button>
474
+ <button onClick={() => setSelected(["react", "typescript", "node"])}>
475
+ Reset to Defaults
476
+ </button>
477
+ </div>
478
+ </div>
479
+ );
480
+ }
481
+ ```
482
+
483
+ ---
484
+
485
+ ## API Reference
486
+
487
+ ### `MultiSelectOption`
488
+
489
+ ```ts
490
+ interface MultiSelectOption {
491
+ value: string; // Unique identifier stored in the value array
492
+ label: string; // Display text shown in the dropdown and badges
493
+ disabled?: boolean; // Prevents this option from being selected
494
+ }
495
+ ```
496
+
497
+ ### `MultiSelectProps`
498
+
499
+ | Prop | Type | Default | Description |
500
+ |---|---|---|---|
501
+ | `options` | `MultiSelectOption[]` | required | Array of selectable options |
502
+ | `value` | `string[]` | `[]` | Currently selected values (controlled) |
503
+ | `onValueChange` | `(value: string[]) => void` | — | Called when selection changes |
504
+ | `placeholder` | `string` | `"Select options..."` | Shown when nothing is selected |
505
+ | `searchPlaceholder` | `string` | `"Search..."` | Placeholder inside the search input |
506
+ | `emptyText` | `string` | `"No options found."` | Shown when search has no results |
507
+ | `disabled` | `boolean` | `false` | Disables the entire component |
508
+ | `maxCount` | `number` | — | Maximum number of selectable items |
509
+ | `clearable` | `boolean` | `true` | Show / hide the clear all control |
510
+ | `className` | `string` | — | Extra classes for the trigger button |
511
+ | `contentClassName` | `string` | — | Extra classes for the dropdown panel |
512
+ | `aria-label` | `string` | — | Accessible label for screen readers |
513
+
514
+ ---
515
+
516
+ ## Keyboard Navigation
517
+
518
+ | Key | Action |
519
+ |---|---|
520
+ | `Space` / `Enter` | Open dropdown / select focused option |
521
+ | `↑` / `↓` | Navigate through options |
522
+ | `Escape` | Close the dropdown |
523
+ | `Tab` | Move focus out of the dropdown |
524
+
525
+ ---
526
+
527
+ ## TypeScript
528
+
529
+ All types are exported from the package root:
530
+
531
+ ```ts
532
+ import { MultiSelect } from "react-multiselect-ui";
533
+ import type { MultiSelectProps, MultiSelectOption } from "react-multiselect-ui";
534
+
535
+ // Build options dynamically with full type safety
536
+ const buildOptions = (
537
+ items: { id: string; name: string }[]
538
+ ): MultiSelectOption[] =>
539
+ items.map((item) => ({ value: item.id, label: item.name }));
540
+ ```
541
+
542
+ ---
543
+
544
+ ## Framework Guides
545
+
546
+ ### Next.js App Router
547
+
548
+ Add `"use client"` at the top of any file that uses the component since it uses React state:
549
+
550
+ ```tsx
551
+ "use client";
552
+
553
+ import { useState } from "react";
554
+ import { MultiSelect } from "react-multiselect-ui";
555
+
556
+ export default function Page() {
557
+ const [selected, setSelected] = useState<string[]>([]);
558
+
559
+ return (
560
+ <MultiSelect
561
+ options={options}
562
+ value={selected}
563
+ onValueChange={setSelected}
564
+ />
565
+ );
566
+ }
73
567
  ```
568
+
569
+ ### Next.js Pages Router
570
+
571
+ Works without any extra configuration:
572
+
573
+ ```tsx
574
+ import { useState } from "react";
575
+ import { MultiSelect } from "react-multiselect-ui";
576
+
577
+ export default function Page() {
578
+ const [selected, setSelected] = useState<string[]>([]);
579
+
580
+ return (
581
+ <MultiSelect
582
+ options={options}
583
+ value={selected}
584
+ onValueChange={setSelected}
585
+ />
586
+ );
587
+ }
588
+ ```
589
+
590
+ ### Vite + React
591
+
592
+ Works out of the box. Just follow the Tailwind setup above.
593
+
594
+ ### Remix
595
+
596
+ ```tsx
597
+ // app/routes/_index.tsx
598
+ import { useState } from "react";
599
+ import { MultiSelect } from "react-multiselect-ui";
600
+
601
+ export default function Index() {
602
+ const [selected, setSelected] = useState<string[]>([]);
603
+
604
+ return (
605
+ <MultiSelect
606
+ options={options}
607
+ value={selected}
608
+ onValueChange={setSelected}
609
+ />
610
+ );
611
+ }
612
+ ```
613
+
614
+ ---
615
+
616
+ ## Troubleshooting
617
+
618
+ ### Component renders with no styles
619
+
620
+ You are missing the Tailwind scan configuration. See the **Tailwind Setup** section above for your version (v3 or v4).
621
+
622
+ ### Dropdown appears behind modals or sticky headers
623
+
624
+ The dropdown uses a Radix UI Portal (mounts directly on `<body>`). Override the z-index via `contentClassName`:
625
+
626
+ ```tsx
627
+ <MultiSelect contentClassName="z-[9999]" ... />
628
+ ```
629
+
630
+ ### TypeScript error: Cannot find module
631
+
632
+ Make sure you import from the package root:
633
+
634
+ ```ts
635
+ // ✅ Correct
636
+ import { MultiSelect } from "react-multiselect-ui";
637
+ import type { MultiSelectOption } from "react-multiselect-ui";
638
+
639
+ // ❌ Wrong — never import from internal paths
640
+ import { MultiSelect } from "react-multiselect-ui/dist/index.mjs";
641
+ ```
642
+
643
+ ### React 17 — JSX transform error
644
+
645
+ Make sure your tsconfig has the new JSX transform:
646
+
647
+ ```json
648
+ {
649
+ "compilerOptions": {
650
+ "jsx": "react-jsx"
651
+ }
652
+ }
653
+ ```
654
+
655
+ ---
656
+
657
+ ## Migrating from `@parag.vora/react-multiselect-ui`
658
+
659
+ ```bash
660
+ # Remove old package
661
+ npm uninstall @parag.vora/react-multiselect-ui
662
+
663
+ # Install new package
664
+ npm install react-multiselect-ui
665
+ ```
666
+
667
+ Update your imports:
668
+
669
+ ```ts
670
+ // Before
671
+ import { MultiSelect } from "@parag.vora/react-multiselect-ui";
672
+
673
+ // After
674
+ import { MultiSelect } from "react-multiselect-ui";
675
+ ```
676
+
677
+ The API is identical — no other changes needed.
678
+
679
+ ---
680
+
681
+ ## Contributing
682
+
683
+ Contributions, issues, and feature requests are welcome!
684
+
685
+ 1. Fork the repository
686
+ 2. Create your branch: `git checkout -b feat/my-feature`
687
+ 3. Commit: `git commit -m "feat: add my feature"`
688
+ 4. Push: `git push origin feat/my-feature`
689
+ 5. Open a Pull Request on GitHub
690
+
691
+ ---
692
+
693
+ ## License
694
+
695
+ MIT © [Parag Vora](mailto:paragvora19@gmail.com)
696
+
697
+ ---
698
+
699
+ ## Links
700
+
701
+ - [npm](https://www.npmjs.com/package/react-multiselect-ui)
702
+ - [GitHub](https://github.com/paragvora23/react-multiselect-ui)
703
+ - [Live Demo](https://react-multiselect-ui.netlify.app)
704
+ - [Report an Issue](https://github.com/paragvora23/react-multiselect-ui/issues)