Skip to content

Filter a product catalog

Bound input, server-side filtering, and updated results in one Astro component.

View Markdown

Query on the server. Render in the same component. This example uses a small local catalog so you can run it without a database; replace the filter callback with your own database query when connecting real products.

Set a maximum price and apply the filter. Try 10 for no results, 50 for two products, or 100 for the full catalog. Negative and empty prices are rejected.

Example workspace
src/pages/products.astro
---
import { BButton, BInput, Bind, BindForm } from '@astro-utils/forms/forms.js';
import Layout from '../layouts/Layout.astro';
import { products } from '../data/products';
const bind = Bind({ maxPrice: 50 });
let matches = products.filter(product => product.price <= bind.maxPrice);
function filterProducts() {
matches = products.filter(product => product.price <= bind.maxPrice);
}
---
<Layout>
<span slot="title">Filter products</span>
<BindForm {bind}>
<label for="maxPrice">Maximum price ($)</label>
<BInput id="maxPrice" name="maxPrice" type="number" min={0} required />
<BButton onClick={filterProducts} whenFormOK>Apply filter</BButton>
<p role="status">{matches.length} products found</p>
<ul>{matches.map(product => <li>{product.name} — ${product.price}</li>)}</ul>
</BindForm>
</Layout>
Preview Interactive demo

Bind restores the submitted budget, BInput validates the field, and BButton runs filterProducts on the server when the form is valid. Astro renders the result count and matching rows together. The embedded preview simulates this interaction locally.

Follow the Forms setup or copy the configuration, middleware, and shared layout from the file sidebar. Add both the page and catalog files at the paths shown.