← Components/Inputs & Forms

MultiSelect

multiselect-1779394345235.tsx
'use client'
import { useState, useRef } from 'react'

const OPTIONS = ['React','Vue','Angular','Svelte','Next.js','Nuxt','Remix','Astro']

export default function MultiSelect({ options = OPTIONS, placeholder = 'Select frameworks...' }) {
  const [open, setOpen] = useState(false)
  const [selected, setSelected] = useState([])
  const [search, setSearch] = useState('')
  const filtered = options.filter(o => o.toLowerCase().includes(search.toLowerCase()))
  const toggle = (opt) => setSelected(s => s.includes(opt) ? s.filter(x => x!==opt) : [...s, opt])
  const all = selected.length === options.length
  return (
    <div style={{ position:'relative', maxWidth:'320px' }}>
      <div onClick={() => setOpen(!open)} style={{
        display:'flex', flexWrap:'wrap', gap:'4px', padding:'8px 12px',
        border:'2px solid ' + (open?'#6d28d9':'#e2e8f0'), borderRadius:'10px',
        cursor:'pointer', minHeight:'44px', alignItems:'center', background:'#fff',
      }}>
        {selected.length === 0 && <span style={{ color:'#94a3b8', fontSize:'14px' }}>{placeholder}</span>}
        {selected.map(s => (
          <span key={s} style={{ background:'#ede9fe', color:'#6d28d9', padding:'2px 8px', borderRadius:'6px', fontSize:'12px', fontWeight:600, display:'flex', alignItems:'center', gap:'4px' }}>
            {s}
            <button onClick={e=>{e.stopPropagation();toggle(s)}} style={{ background:'none', border:'none', color:'#7c3aed', cursor:'pointer', fontSize:'14px', padding:0 }}>×</button>
          </span>
        ))}
        <span style={{ marginLeft:'auto', color:'#94a3b8', fontSize:'14px' }}>{open?'▲':'▼'}</span>
      </div>
      {open && (
        <div style={{ position:'absolute', top:'calc(100%+4px)', left:0, right:0, background:'#fff', border:'1px solid #e2e8f0', borderRadius:'10px', boxShadow:'0 8px 30px rgba(0,0,0,0.1)', zIndex:100, overflow:'hidden', marginTop:'4px' }}>
          <div style={{ padding:'10px' }}>
            <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search..." style={{ width:'100%', border:'1px solid #e2e8f0', borderRadius:'6px', padding:'6px 10px', fontSize:'13px', outline:'none', boxSizing:'border-box' }} />
          </div>
          <div onClick={()=>setSelected(all?[]:options)} style={{ padding:'8px 14px', fontSize:'13px', fontWeight:600, color:'#6d28d9', borderBottom:'1px solid #f1f5f9', cursor:'pointer', background:'#faf5ff' }}>
            {all ? 'Deselect All' : 'Select All'}
          </div>
          <div style={{ maxHeight:'200px', overflowY:'auto' }}>
            {filtered.map(opt => (
              <div key={opt} onClick={()=>toggle(opt)} style={{
                display:'flex', alignItems:'center', gap:'10px', padding:'10px 14px',
                cursor:'pointer', fontSize:'14px', color:selected.includes(opt)?'#6d28d9':'#374151',
                background:selected.includes(opt)?'#faf5ff':'transparent',
              }}>
                <div style={{ width:'16px', height:'16px', borderRadius:'4px', border:'2px solid '+(selected.includes(opt)?'#6d28d9':'#cbd5e1'), background:selected.includes(opt)?'#6d28d9':'transparent', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
                  {selected.includes(opt) && <span style={{ color:'#fff', fontSize:'10px' }}>✓</span>}
                </div>
                {opt}
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  )
}

Component info

CategoryInputs & Forms
Frameworkreact
TierFREE
Views0
Copies0

About

Multi-select dropdown with search, badges and select-all option

More from Inputs & Forms

'use client';

import { useState, useEffect } from 'react';

interface Tag {
  id: number;
  name: string;
}

const TagInput = () => {
  const [tags, setTags] = useState<Tag[]>([]);
  const [inputValue, setInputValue] = useState('');
  const [suggest
TagInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface File {
  name: string;
  size: number;
  progress: number;
}

const FileUpload = () => {
  const [dragOver, setDragOver] = useState(false);
  const [files, setFiles] = useState<File[]
FileUpload
Inputs & Forms
import React, { useState } from 'react';

const OTPInput = () => {
  const [otp, setOtp] = useState(new Array(6).fill(''));
  const [activeIndex, setActiveIndex] = useState(0);

  const handleChange = (e, index) => {
    const value = e.target.value;
OTPInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface RangeSliderProps {
  min: number;
  max: number;
  defaultValue: [number, number];
}

const RangeSlider: React.FC<RangeSliderProps> = ({ min, max, defaultValue }) => {
  const [minVal
RangeSlider
Inputs & Forms