src/components/forms/FormFilter.astro
---
/**
* FormFilter — filter-/zoekbalk met zoekveld en groepen van checkbox-filters.
*
* Props:
* - headline?: string
* - searchPlaceholder?: string
* - groups?: { label: string; options: string[] }[]
* - submitLabel?: string
* - resetLabel?: string
* - action?: string
*/
interface Props {
headline?: string;
searchPlaceholder?: string;
groups?: { label: string; options: string[] }[];
submitLabel?: string;
resetLabel?: string;
action?: string;
}
const {
headline = 'Filter resultaten',
searchPlaceholder = 'Zoek op trefwoord…',
groups = [
{ label: 'Dienst', options: ['SEO', 'Google Ads', 'Social Media', 'Webdesign', 'Branding'] },
{ label: 'Budget', options: ['< € 500 / mnd', '€ 500–1.000', '€ 1.000–2.500', '> € 2.500'] },
{ label: 'Branche', options: ['E-commerce', 'B2B', 'Horeca', 'Zorg', 'Technologie'] },
],
submitLabel = 'Resultaten tonen',
resetLabel = 'Filters wissen',
action = '#',
} = Astro.props;
---
<section class="bl-section ffl">
<div class="bl-inner bl-inner--narrow ffl__inner">
{headline && <h2 class="ffl__headline">{headline}</h2>}
<form class="ffl__form" action={action} novalidate>
<div class="ffl__search-wrap">
<input class="ffl__search" type="search" placeholder={searchPlaceholder} aria-label={searchPlaceholder} />
<button class="ffl__search-btn" type="submit" aria-label="Zoeken">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
</button>
</div>
<div class="ffl__filters">
{groups.map((g, gi) => (
<div class="ffl__group">
<span class="ffl__group-label">{g.label}</span>
<div class="ffl__checkboxes">
{g.options.map((opt) => (
<label class="ffl__checkbox">
<input type="checkbox" name={`filter-${gi}`} value={opt} /> <span>{opt}</span>
</label>
))}
</div>
</div>
))}
</div>
<div class="ffl__actions">
<button class="ffl__btn" type="submit">{submitLabel}</button>
<button class="ffl__reset" type="reset">{resetLabel}</button>
</div>
</form>
</div>
</section>
<style>
.ffl{background:#f9f9fb}
.ffl__headline{font-size:clamp(1.5rem,3vw,1.75rem);font-weight:800;color:var(--color-primary, #0a0a0a);letter-spacing:-.02em;margin:0 0 1.5rem}
.ffl__form{display:flex;flex-direction:column;gap:1.5rem}
.ffl__search-wrap{position:relative;max-width:520px}
.ffl__search{width:100%;box-sizing:border-box;padding:.75rem 3rem .75rem 1rem;border:1.5px solid #d1d5db;border-radius:8px;font-size:1rem;background:#fff;outline:none;font-family:inherit;transition:border-color .2s}
.ffl__search:focus{border-color:var(--color-accent, #6366f1)}
.ffl__search-btn{position:absolute;right:.75rem;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:#6b7280;display:flex;align-items:center}
.ffl__filters{display:flex;flex-wrap:wrap;gap:1.5rem}
.ffl__group{display:flex;flex-direction:column;gap:.5rem;min-width:160px}
.ffl__group-label{font-size:.8125rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#374151}
.ffl__checkboxes{display:flex;flex-direction:column;gap:.4rem}
.ffl__checkbox{display:flex;align-items:center;gap:.5rem;font-size:1rem;color:var(--color-primary, #0a0a0a);cursor:pointer}
.ffl__checkbox input[type=checkbox]{accent-color:var(--color-accent, #6366f1);width:15px;height:15px;cursor:pointer}
.ffl__actions{display:flex;gap:1rem;align-items:center}
.ffl__btn{padding:.8rem 1.75rem;background:var(--color-accent, #6366f1);color:#fff;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;transition:opacity .2s}
.ffl__btn:hover{opacity:.88}
.ffl__reset{background:none;border:none;font-size:.9375rem;color:#6b7280;cursor:pointer;text-decoration:underline;font-family:inherit}
.ffl__reset:hover{color:#0a0a0a}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
headline | string | 'Filter resultaten' | Koptekst |
searchPlaceholder | string | - | Placeholder zoekveld |
groups | { label: string; options: string[] }[] | - | Filtergroepen |
submitLabel | string | 'Resultaten tonen' | Label submit-knop |
resetLabel | string | 'Filters wissen' | Label reset-knop |
action | string | '#' | Form action URL |
* = verplicht