TAG_SELECTOR_COMPONENT.md

Component documentation for the TagSelector tag management interface.

Overview

The TagSelector component provides an intuitive interface for selecting and managing tags. It supports both predefined tags from a database and custom user-created tags, with intelligent suggestions and validation.

Component Location

  • File: src/components/TagSelector.tsx
  • Type: Form Input Component
  • Framework: React with TypeScript

Features

  • Dual Tag Sources: Supports both predefined and custom tags
  • Intelligent Suggestions: Filters available tags based on user input
  • Custom Tag Creation: Allows users to create new tags on-the-fly
  • Tag Limit Enforcement: Configurable maximum number of tags
  • Visual Feedback: Clear distinction between official and custom tags
  • Keyboard Navigation: Enter key support for tag creation
  • Real-time Validation: Input validation and error handling

Props Interface

interface TagSelectorProps {
  selectedTags: string[];                    // Currently selected tag IDs
  availableTags?: Tag[];                     // Database tags to suggest
  onChange: (tags: string[]) => void;        // Callback when tags change
  placeholder?: string;                      // Input placeholder text
  maxTags?: number;                          // Maximum allowed tags (default: 10)
  allowCustomTags?: boolean;                 // Enable custom tag creation (default: true)
  className?: string;                        // Additional CSS classes
}

Tag Data Structure

interface Tag {
  id: string;           // Unique identifier
  name: string;         // Display name
  description?: string; // Optional description for tooltips
}

Usage Examples

Basic Implementation

import { TagSelector } from '@/components/TagSelector';
import { useState } from 'react';

function AssistantForm() {
  const [selectedTags, setSelectedTags] = useState<string[]>([]);
  const [availableTags] = useState<Tag[]>([
    { id: 'ai', name: 'AI Assistant', description: 'General AI functionality' },
    { id: 'coding', name: 'Code Helper', description: 'Programming assistance' },
    { id: 'writing', name: 'Writing Aid', description: 'Text composition help' }
  ]);

  return (
    <TagSelector
      selectedTags={selectedTags}
      availableTags={availableTags}
      onChange={setSelectedTags}
      placeholder="Add relevant tags..."
      maxTags={5}
    />
  );
}

Read-Only Mode (No Custom Tags)

<TagSelector
  selectedTags={selectedTags}
  availableTags={predefinedTags}
  onChange={setSelectedTags}
  allowCustomTags={false}
  placeholder="Select from available tags..."
/>

High Tag Limit for Flexible Use

<TagSelector
  selectedTags={selectedTags}
  availableTags={availableTags}
  onChange={setSelectedTags}
  maxTags={20}
  placeholder="Add multiple tags..."
/>

Tag Suggestion Logic

The component intelligently filters suggestions based on user input:

useEffect(() => {
  if (inputValue.trim() && availableTags.length > 0) {
    const filtered = availableTags.filter(
      tag => 
        tag.name.toLowerCase().includes(inputValue.toLowerCase()) &&
        !selectedTags.includes(tag.id)  // Exclude already selected tags
    );
    setSuggestions(filtered);
    setShowSuggestions(filtered.length > 0);
  } else {
    setSuggestions([]);
    setShowSuggestions(false);
  }
}, [inputValue, availableTags, selectedTags]);

Tag Creation Workflow

Adding Predefined Tags

  1. User types in input field
  2. Matching suggestions appear in dropdown
  3. User clicks suggestion or presses Enter
  4. Tag is added to selected list

Creating Custom Tags

  1. User types text that doesn’t match existing tags
  2. “Create [tag name]” option appears in dropdown
  3. User clicks option or presses Enter
  4. Custom tag is added with input text as both ID and name
const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
  if (e.key === 'Enter' && inputValue.trim()) {
    e.preventDefault();
    
    // Check for matching suggestion
    const matchingTag = suggestions.find(
      tag => tag.name.toLowerCase() === inputValue.trim().toLowerCase()
    );

    if (matchingTag) {
      handleAddTag(matchingTag.id);
    } else if (allowCustomTags) {
      // Add as custom tag
      handleAddTag(inputValue.trim());
    }
  }
};

Tag Display and Management

Selected Tags Visualization

<div className="flex flex-wrap gap-2">
  {selectedTags.map((tagId) => (
    <Badge key={tagId} variant="secondary" className="flex items-center gap-1">
      <TagIcon className="h-3 w-3" />
      <span>{getTagDisplay(tagId)}</span>
      {isCustomTag(tagId) && (
        <span className="text-xs text-muted-foreground">(custom)</span>
      )}
      <button onClick={() => handleRemoveTag(tagId)}>
        <X className="h-3 w-3" />
      </button>
    </Badge>
  ))}
</div>

Tag Limit Enforcement

const handleAddTag = (tagId: string) => {
  if (selectedTags.length >= maxTags) {
    return;  // Silently reject if at limit
  }

  if (!selectedTags.includes(tagId)) {
    onChange([...selectedTags, tagId]);
  }
  setInputValue('');
  setShowSuggestions(false);
};

Suggestions Dropdown

The component displays intelligent suggestions with descriptions:

{showSuggestions && (
  <div className="absolute top-full left-0 right-0 mt-1 bg-background border rounded-md shadow-lg z-10">
    {suggestions.map((tag) => (
      <button
        key={tag.id}
        className="w-full text-left px-3 py-2 hover:bg-muted"
        onClick={() => handleAddTag(tag.id)}
      >
        <div className="flex items-center gap-2">
          <TagIcon className="h-4 w-4" />
          <div className="flex-1">
            <div className="text-sm font-medium">{tag.name}</div>
            {tag.description && (
              <div className="text-xs text-muted-foreground">{tag.description}</div>
            )}
          </div>
        </div>
      </button>
    ))}
    
    {/* Custom tag creation option */}
    {allowCustomTags && !matchingTag && (
      <button
        className="w-full text-left px-3 py-2 border-t"
        onClick={() => handleAddTag(inputValue.trim())}
      >
        <div className="flex items-center gap-2">
          <Plus className="h-4 w-4" />
          <div>
            <div className="text-sm">Create "{inputValue.trim()}"</div>
            <div className="text-xs text-muted-foreground">Add as custom tag</div>
          </div>
        </div>
      </button>
    )}
  </div>
)}

Utility Functions

Tag Display Resolution

const getTagDisplay = (tagId: string): string => {
  const tag = availableTags.find(t => t.id === tagId);
  return tag ? tag.name : tagId;  // Use name if available, fallback to ID
};

Custom Tag Detection

const isCustomTag = (tagId: string): boolean => {
  return !availableTags.some(tag => tag.id === tagId);
};

Accessibility Features

  • ARIA Labels: Proper labeling for screen readers
  • Keyboard Navigation: Full keyboard support
  • Focus Management: Proper focus handling in dropdowns
  • Semantic HTML: Use of proper form elements

Styling and Theming

Container Styling

.space-y-4  /* Vertical spacing between elements */

Tag Badge Styling

.flex items-center gap-1 pl-2 pr-1 py-1  /* Badge spacing */

Input Field

.pr-8  /* Right padding for counter */

Suggestions Dropdown

.absolute top-full left-0 right-0 mt-1 bg-background border rounded-md shadow-lg z-10 max-h-48 overflow-y-auto

Error Handling

  • Prevents duplicate tag selection
  • Enforces maximum tag limits
  • Handles empty input gracefully
  • Safe string manipulation for custom tags

Performance Considerations

  • Efficient filtering with array methods
  • Debounced suggestion updates
  • Minimal re-renders with proper state management
  • Optimized event handling

Dependencies

UI Components

  • @/components/ui/input for text input
  • @/components/ui/button for actions
  • @/components/ui/badge for tag display
  • @/components/ui/label for form labeling

Icons

  • Lucide React icons (Tag, Plus, X)

Utilities

  • @/lib/utils for class name utilities
  • Form components that use tag selection
  • Database tag management interfaces
  • Assistant configuration forms
  • Content categorization systems