Overview
The SearchFormSection component provides a comprehensive search interface for job listings. It includes a text search input and multiple filter dropdowns (technology, location, experience level) with real-time updates.
Usage
import { SearchFormSection } from '@/components'
import { useState } from 'react'
function JobSearchPage () {
const [ searchText , setSearchText ] = useState ( '' )
const [ filters , setFilters ] = useState ({})
const handleTextFilter = ( text ) => {
setSearchText ( text )
}
const handleSearch = ( formData ) => {
setFilters ( formData )
// Apply filters to job listings
}
return (
< SearchFormSection
onTextFilter = { handleTextFilter }
onSearch = { handleSearch }
initialTextInput = { searchText }
/>
)
}
Props
Callback function called when the search text changes. Receives the current text value. onTextFilter : ( text : string ) => void
Callback function called when any form field changes. Receives the complete form data object. onSearch : ( formData : FormData ) => void
Initial value for the text search input field
Features
Text Search
The main search input allows users to search for jobs, companies, or skills:
< input
name = { idText }
id = "empleos-search-input"
type = "text"
ref = { inputRef }
defaultValue = { initialTextInput }
placeholder = "Buscar trabajos, empresas o habilidades"
onChange = { handleTextChange }
/>
Technology Filter
Dropdown with popular technologies organized in groups:
Popular Technologies: JavaScript, Python, React, Node.js
Other Technologies: Java, C#, C, C++, Ruby, PHP
< select name = { idTechnology } id = "filter-technology" ref = { selectRefTechnology } >
< option value = "" > Tecnología </ option >
< optgroup label = "Tecnologías populares" >
< option value = "javascript" > JavaScript </ option >
< option value = "python" > Python </ option >
< option value = "react" > React </ option >
< option value = "nodejs" > Node.js </ option >
</ optgroup >
{ /* More options... */ }
</ select >
Location Filter
Dropdown with available job locations:
Remoto
Ciudad de México
Guadalajara
Monterrey
Barcelona
Experience Level Filter
Dropdown with experience levels:
Junior
Mid-level
Senior
Lead
A clear button (“x”) that resets all form fields:
< button onClick = { handleClearFilters } type = "button" aria-label = "Clear search input" className = "clear-input-button" >
x
</ button >
Component Structure
Full Component (Simplified)
Basic Usage
With Job Filtering
import { useId } from "react"
import { useSearchForm } from "@/hooks/useSearchForm"
export function SearchFormSection ({ onTextFilter , onSearch , initialTextInput }) {
const idText = useId ()
const idTechnology = useId ()
const idLocation = useId ()
const idExperienceLevel = useId ()
const {
handleSubmit ,
handleTextChange ,
handleClearFilters ,
inputRef ,
selectRefTechnology ,
selectRefLocation ,
selectRefExperienceLevel
} = useSearchForm ({
onTextFilter ,
onSearch ,
idTechnology ,
idLocation ,
idExperienceLevel ,
idText
})
return (
< section className = "jobs-search" >
< h1 > Encuentra tu próximo trabajo </ h1 >
< p > Explora miles de oportunidades en el sector tecnológico. </ p >
< form onChange = { handleSubmit } id = "empleos-search-form" role = "search" >
< div className = "search-bar" >
< svg > { /* Search icon */ } </ svg >
< input
name = { idText }
type = "text"
ref = { inputRef }
defaultValue = { initialTextInput }
placeholder = "Buscar trabajos, empresas o habilidades"
onChange = { handleTextChange }
/>
< button onClick = { handleClearFilters } type = "button" aria-label = "Clear search input" >
x
</ button >
</ div >
< div className = "search-filters" >
< select name = { idTechnology } ref = { selectRefTechnology } >
{ /* Technology options */ }
</ select >
< select name = { idLocation } ref = { selectRefLocation } >
{ /* Location options */ }
</ select >
< select name = { idExperienceLevel } ref = { selectRefExperienceLevel } >
{ /* Experience level options */ }
</ select >
</ div >
</ form >
</ section >
)
}
Custom Hook Integration
The component uses the useSearchForm custom hook to manage form state and behavior:
const {
handleSubmit , // Form submit handler
handleTextChange , // Text input change handler
handleClearFilters , // Clear all filters
inputRef , // Ref for text input
selectRefTechnology , // Ref for technology select
selectRefLocation , // Ref for location select
selectRefExperienceLevel // Ref for experience select
} = useSearchForm ({
onTextFilter ,
onSearch ,
idTechnology ,
idLocation ,
idExperienceLevel ,
idText
})
The onSearch callback receives a FormData object with the following structure:
{
[ idText ]: "react developer" , // Search text
[ idTechnology ]: "react" , // Selected technology
[ idLocation ]: "remoto" , // Selected location
[ idExperienceLevel ]: "senior" // Selected experience level
}
Note: The field names are generated using React’s useId() hook for uniqueness.
Styling
The component uses global CSS classes:
jobs-search - Main section container
search-bar - Search input container
search-filters - Filter dropdowns container
clear-input-button - Clear button styling
Usage Patterns
Real-time Search
import { SearchFormSection } from '@/components'
import { useState , useEffect } from 'react'
import { useDebounce } from '@/hooks/useDebounce'
function RealTimeSearch () {
const [ searchText , setSearchText ] = useState ( '' )
const [ filters , setFilters ] = useState ({})
const debouncedSearch = useDebounce ( searchText , 300 )
useEffect (() => {
// Perform search when debounced value changes
performSearch ( debouncedSearch , filters )
}, [ debouncedSearch , filters ])
return (
< SearchFormSection
onTextFilter = { setSearchText }
onSearch = { setFilters }
initialTextInput = { searchText }
/>
)
}
With URL Parameters
import { SearchFormSection } from '@/components'
import { useSearchParams } from 'react-router-dom'
function SearchWithUrl () {
const [ searchParams , setSearchParams ] = useSearchParams ()
const handleSearch = ( formData ) => {
// Convert FormData to URLSearchParams
const params = {}
for ( let [ key , value ] of formData . entries ()) {
if ( value ) params [ key ] = value
}
setSearchParams ( params )
}
return (
< SearchFormSection
onTextFilter = { () => {} }
onSearch = { handleSearch }
initialTextInput = { searchParams . get ( 'search' ) || '' }
/>
)
}
Filter Job Listings
function filterJobs ( jobs , formData , textQuery ) {
return jobs . filter ( job => {
// Text search
if ( textQuery ) {
const searchableText = `
${ job . titulo }
${ job . empresa }
${ job . descripcion }
` . toLowerCase ()
if ( ! searchableText . includes ( textQuery . toLowerCase ())) {
return false
}
}
// Technology filter
const technology = formData . get ( 'technology' )
if ( technology && job . data . technology !== technology ) {
return false
}
// Location filter
const location = formData . get ( 'location' )
if ( location && job . ubicacion !== location ) {
return false
}
// Experience level filter
const level = formData . get ( 'experienceLevel' )
if ( level && job . data . nivel !== level ) {
return false
}
return true
})
}
Accessibility
Uses semantic <section> element
Form has role="search" for screen readers
Clear button has aria-label="Clear search input"
Input has descriptive placeholder text
All form controls have associated labels (via useId)
Source Code
Location: src/components/SearchFormSection/SearchFormSection.jsx:4
Dependencies
react - For useId hook
@/hooks/useSearchForm - Custom hook for form state management
JobListings Display filtered job results
Pagination Paginate search results
Best Practices
Debounce text input - Avoid excessive filtering on every keystroke
Persist filters - Save filter state to URL parameters for shareable links
Show result count - Display how many jobs match the current filters
Clear feedback - Indicate when filters are active
Handle empty results - Use JobListings component which handles empty states
Mobile responsive - Ensure filters work well on small screens
Loading states - Show loading indicator while filtering large datasets