Skip to main content

Overview

The FilterSidebar component provides a comprehensive filtering interface for property searches. It fetches metadata from the API, displays collapsible filter sections, and manages filter state with real-time updates.

Import

import FilterSidebar from "../components/FilterSidebar";

Props

isOpen
boolean
required
Controls the visibility of the sidebar on mobile devices. On desktop (lg breakpoint), the sidebar is always visible.
onClose
() => void
required
Callback function triggered when the user closes the sidebar (mobile only).
searchFilters
PropertyFilters
required
Current filter state object containing all active filters.
setSearchFilters
(filters: PropertyFilters) => void
required
Function to update the filter state.

PropertyFilters Type

The PropertyFilters interface includes:
propertyType
string[]
Array of property type slugs (e.g., [“casa”, “departamento”])
listingType
string[]
Array of listing type slugs (e.g., [“venta”, “alquiler”])
bedrooms
number
Minimum number of bedrooms
bathrooms
number
Minimum number of bathrooms
minPrice
number
Minimum price filter
maxPrice
number
Maximum price filter
query
string
Search query string
location
string
Location search string

Features

Metadata Integration

The component automatically fetches filter options from the API on mount:
  • Property types (casa, departamento, terreno, local)
  • Operation types (venta, alquiler, venta-y-alquiler)
  • Fallback to hardcoded values if API fails

Collapsible Sections

All filter sections can be expanded/collapsed:
  • Default expanded: Property Type, Listing Type, Price, Bedrooms, Bathrooms
  • Chevron icons indicate section state
  • Smooth transitions for expand/collapse

Filter Sections

Property Type (Tipo de Propiedad)

Checkbox list of available property types:
  • Casa (House)
  • Departamento (Apartment)
  • Terreno (Land)
  • Local (Commercial space)

Listing Type (Tipo de Operación)

Checkbox list of operation types:
  • Venta (Sale)
  • Alquiler (Rent)
  • Venta y Alquiler (Sale and Rent)

Bedrooms (Dormitorios)

Button group for minimum bedroom count:
  • Options: 1+, 2+, 3+, 4+, 5+
  • Click to select, click again to deselect
  • Red highlight for selected option

Bathrooms (Baños)

Button group for minimum bathroom count:
  • Options: 1+, 2+, 3+, 4+
  • Click to select, click again to deselect
  • Red highlight for selected option

Responsive Design

  • Fixed overlay sidebar
  • Slides in from left
  • Dark overlay backdrop
  • Close button in header
  • Full height design

Usage Examples

import FilterSidebar from "../components/FilterSidebar";
import { useState } from "react";
import type { PropertyFilters } from "../types/api";

function PropertyListings() {
  const [isFilterOpen, setIsFilterOpen] = useState(false);
  const [filters, setFilters] = useState<PropertyFilters>({
    propertyType: [],
    listingType: [],
  });

  return (
    <div className="flex gap-6">
      {/* Mobile filter toggle */}
      <button
        onClick={() => setIsFilterOpen(true)}
        className="lg:hidden"
      >
        Show Filters
      </button>

      {/* Filter Sidebar */}
      <FilterSidebar
        isOpen={isFilterOpen}
        onClose={() => setIsFilterOpen(false)}
        searchFilters={filters}
        setSearchFilters={setFilters}
      />

      {/* Property Grid */}
      <div className="flex-1">
        {/* Render properties based on filters */}
      </div>
    </div>
  );
}

Internal Components

FilterSection

Internal component for collapsible filter sections:
<FilterSection title="Tipo de Propiedad" section="propertyType">
  {/* Filter options */}
</FilterSection>

CheckboxOption

Internal component for checkbox filter items:
<CheckboxOption
  value="casa"
  label="Casa"
  checked={isChecked}
  onChange={handleChange}
/>

Loading State

While fetching metadata, displays:
  • Skeleton sidebar structure
  • Loading spinner (using Loader2 icon)
  • Same header layout

Error Handling

If metadata fetch fails:
  • Displays yellow warning banner
  • Falls back to basic filter options
  • App remains functional

Styling

Desktop Styles

  • Width: w-80 (320px)
  • Position: sticky with top-4
  • Max height: max-h-[calc(100vh-120px)]
  • Border and rounded corners

Mobile Styles

  • Full height overlay
  • Slide-in animation from left
  • Dark backdrop (bg-black bg-opacity-60)
  • Z-index: z-50 for sidebar, z-40 for backdrop

Accessibility

  • All buttons have aria-label attributes
  • Keyboard navigation support with tabIndex={0}
  • Section toggles have descriptive labels
  • Semantic HTML structure
  • Focus states on all interactive elements

Dependencies

  • lucide-react - Icons (X, ChevronDown, ChevronUp, Loader2)
  • react - State management
  • api - Metadata fetching

API Integration

Fetches metadata using:
const response = await api.metadata.getAll();
Expected response structure:
{
  data: {
    propertyTypes: Array<{ id: number; name: string; slug: string }>,
    operationTypes: Array<{ id: number; name: string; slug: string }>
  }
}

Source Code

View the full implementation at src/components/FilterSidebar.tsx:1

Build docs developers (and LLMs) love