Component

Filter Menu

Data filtering dropdown with checkboxes, status indicators, categories, count badges, and date range picker.

  • Component
  • Tailwind
  • HTML
  • MIT

Preview

Live component

Interactive preview
Open preview
9:41 100%
devsnips.dev/library/tailwind/components/dropdowns/filter-menu/
fluid · no fixed width 100%
No dependencies Production-ready

Install

Add to your project

terminal
npx devsnips add Tailwind/Components/Dropdowns/filter-menu
registry path: Tailwind/Components/Dropdowns/filter-menu

Source

Implementation

code.html
<!-- Filter Menu -->
<div class="relative inline-block">
  <button
    id="filter-button"
    class="inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors"
    onclick="toggleDropdown('filter-menu')"
  >
    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"></path>
    </svg>
    <span>Filters</span>
    <span id="filter-count" class="hidden px-1.5 py-0.5 text-xs font-medium text-white bg-blue-600 rounded-full">0</span>
    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
    </svg>
  </button>

  <div
    id="filter-menu"
    class="hidden absolute left-0 z-20 mt-2 w-80 bg-white rounded-xl shadow-xl border border-gray-200 overflow-hidden"
  >
    <div class="px-4 py-3 border-b border-gray-100 flex items-center justify-between">
      <h3 class="font-semibold text-gray-900">Filters</h3>
      <button class="text-xs font-medium text-blue-600 hover:text-blue-700" onclick="clearFilters()">Clear all</button>
    </div>

    <!-- Status Filter -->
    <div class="p-4 border-b border-gray-100">
      <h4 class="text-sm font-medium text-gray-700 mb-3">Status</h4>
      <div class="space-y-2">
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="status" data-value="active" onchange="updateFilters()">
          <span class="flex items-center gap-2 text-sm text-gray-600 group-hover:text-gray-900">
            <span class="w-2 h-2 bg-emerald-500 rounded-full"></span>
            Active
          </span>
          <span class="ml-auto text-xs text-gray-400">(124)</span>
        </label>
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="status" data-value="pending" onchange="updateFilters()">
          <span class="flex items-center gap-2 text-sm text-gray-600 group-hover:text-gray-900">
            <span class="w-2 h-2 bg-amber-500 rounded-full"></span>
            Pending
          </span>
          <span class="ml-auto text-xs text-gray-400">(38)</span>
        </label>
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="status" data-value="inactive" onchange="updateFilters()">
          <span class="flex items-center gap-2 text-sm text-gray-600 group-hover:text-gray-900">
            <span class="w-2 h-2 bg-gray-400 rounded-full"></span>
            Inactive
          </span>
          <span class="ml-auto text-xs text-gray-400">(12)</span>
        </label>
      </div>
    </div>

    <!-- Category Filter -->
    <div class="p-4 border-b border-gray-100">
      <h4 class="text-sm font-medium text-gray-700 mb-3">Category</h4>
      <div class="space-y-2">
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="category" data-value="design" onchange="updateFilters()">
          <span class="text-sm text-gray-600 group-hover:text-gray-900">Design</span>
          <span class="ml-auto text-xs text-gray-400">(56)</span>
        </label>
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="category" data-value="development" onchange="updateFilters()">
          <span class="text-sm text-gray-600 group-hover:text-gray-900">Development</span>
          <span class="ml-auto text-xs text-gray-400">(89)</span>
        </label>
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="category" data-value="marketing" onchange="updateFilters()">
          <span class="text-sm text-gray-600 group-hover:text-gray-900">Marketing</span>
          <span class="ml-auto text-xs text-gray-400">(34)</span>
        </label>
        <label class="flex items-center gap-3 cursor-pointer group">
          <input type="checkbox" class="filter-checkbox w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" data-filter="category" data-value="sales" onchange="updateFilters()">
          <span class="text-sm text-gray-600 group-hover:text-gray-900">Sales</span>
          <span class="ml-auto text-xs text-gray-400">(45)</span>
        </label>
      </div>
    </div>

    <!-- Date Range Filter -->
    <div class="p-4">
      <h4 class="text-sm font-medium text-gray-700 mb-3">Date Range</h4>
      <div class="grid grid-cols-2 gap-2">
        <input type="date" class="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="From">
        <input type="date" class="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="To">
      </div>
    </div>

    <!-- Footer -->
    <div class="px-4 py-3 bg-gray-50 border-t border-gray-100 flex items-center justify-between">
      <span id="filter-summary" class="text-xs text-gray-500">No filters applied</span>
      <button class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors" onclick="applyFilters()">
        Apply Filters
      </button>
    </div>
  </div>
</div>

<script>
  function toggleDropdown(id) {
    document.getElementById(id).classList.toggle('hidden');
  }

  function updateFilters() {
    const checked = document.querySelectorAll('.filter-checkbox:checked');
    const countEl = document.getElementById('filter-count');
    const summaryEl = document.getElementById('filter-summary');
    
    if (checked.length > 0) {
      countEl.textContent = checked.length;
      countEl.classList.remove('hidden');
      summaryEl.textContent = `${checked.length} filter${checked.length > 1 ? 's' : ''} applied`;
    } else {
      countEl.classList.add('hidden');
      summaryEl.textContent = 'No filters applied';
    }
  }

  function clearFilters() {
    document.querySelectorAll('.filter-checkbox').forEach(cb => cb.checked = false);
    updateFilters();
  }

  function applyFilters() {
    toggleDropdown('filter-menu');
  }

  document.addEventListener('click', function(event) {
    const container = document.querySelector('.relative.inline-block');
    if (!container.contains(event.target)) {
      document.getElementById('filter-menu').classList.add('hidden');
    }
  });
</script>
139 lines UTF-8 · LF · Spaces: 2

AI-ready

Available to your agent.

This component is reachable through the DevSnips CLI, MCP server and Skills integrations — one registry, one resource path.

Resource path

devsnips://components/dropdowns/filter-menu

Continue browsing

View all