← Components/Inputs & Forms

TagInput

taginput-1779393692749.tsx
'use client'
import { useState, useRef } from 'react'

export default function TagInput({ placeholder = 'Add tag...' }) {
  const [tags, setTags] = useState(['react', 'typescript'])
  const [input, setInput] = useState('')
  const ref = useRef(null)
  const addTag = () => {
    const val = input.trim().toLowerCase()
    if (val && !tags.includes(val)) setTags(t => [...t, val])
    setInput('')
  }
  const handleKey = (e) => {
    if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); addTag() }
    if (e.key === 'Backspace' && !input) setTags(t => t.slice(0, -1))
  }
  return (
    <div
      onClick={() => ref.current?.focus()}
      style={{
        display: 'flex', flexWrap: 'wrap', gap: '6px',
        border: '2px solid #e2e8f0', borderRadius: '10px', padding: '8px 12px',
        cursor: 'text', minHeight: '48px', alignItems: 'center',
      }}
    >
      {tags.map(tag => (
        <span key={tag} style={{
          display: 'inline-flex', alignItems: 'center', gap: '4px',
          background: '#ede9fe', color: '#6d28d9',
          padding: '3px 10px', borderRadius: '6px', fontSize: '13px', fontWeight: 500,
        }}>
          {tag}
          <button onClick={() => setTags(t => t.filter(x => x !== tag))} style={{
            background: 'none', border: 'none', color: '#7c3aed', cursor: 'pointer', fontSize: '14px', padding: 0
          }}>×</button>
        </span>
      ))}
      <input
        ref={ref} value={input}
        onChange={e => setInput(e.target.value)}
        onKeyDown={handleKey} onBlur={addTag}
        placeholder={tags.length === 0 ? placeholder : ''}
        style={{ border: 'none', outline: 'none', fontSize: '14px', minWidth: '80px', flex: 1 }}
      />
    </div>
  )
}

Component info

CategoryInputs & Forms
Frameworkreact
TierFREE
Views0
Copies0

About

Multi-tag input with keyboard navigation and delete support

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