Search
Simple Search
News Item
The News Item content type can be used to display News content on the website.
CMS Quadrant
CMS landscape quadrant showing Visual Editing vs Frontend Freedom
Site Footer
Footer with social links and copyright
News Item View
Layout template for News Item content type pages
Event View
Layout template for Event content type pages
Block Reference Layout
Template for code examples at the bottom of block reference pages
Search with Facets
Filter by
Advanced
Lazy loading the bridge, authentication with getAccessToken, and preventing reloads
Deployment Patterns
How to deploy Hydra with SPA, SSG/SSR, or scale-to-zero setups
Templates & Layouts
Configure templates in initBridge, use fixed/placeholder blocks, and render with expandTemplatesSync
Listings & Dynamic Blocks
Using expandListingBlocks with a fetchItems map for listings, paging, and dynamic content
Container Blocks
How to use blocks_layout and object_list widgets for containers, with rendering examples
Custom Blocks
Define custom block types, schema enhancers, and block conversion mappings.
Developer Reference
Schema
Pass this object inside the blocks option when calling initBridge() to register this block type with the admin UI. See Custom Blocks for the full setup guide.
{
"search": {
"blockSchema": {
"properties": {
"facetsTitle": {
"title": "Facets Title"
},
"facets": {
"title": "Facets",
"widget": "object_list",
"typeField": "type",
"allowedBlocks": [
"checkboxFacet",
"selectFacet",
"daterangeFacet",
"toggleFacet"
]
},
"listing": {
"title": "Listing",
"widget": "blocks_layout",
"allowedBlocks": [
"listing"
]
}
}
}
},
"checkboxFacet": {
"blockSchema": {
"properties": {
"title": {
"title": "Label"
},
"field": {
"title": "Field",
"widget": "select_querystring_field"
},
"multiple": {
"title": "Multiple choices?",
"type": "boolean",
"default": false
},
"hidden": {
"title": "Hide facet?",
"type": "boolean",
"default": false
}
}
}
},
"selectFacet": {
"blockSchema": {
"properties": {
"title": {
"title": "Label"
},
"field": {
"title": "Field",
"widget": "select_querystring_field"
},
"hidden": {
"title": "Hide facet?",
"type": "boolean",
"default": false
}
}
}
},
"daterangeFacet": {
"blockSchema": {
"properties": {
"title": {
"title": "Label"
},
"field": {
"title": "Field",
"widget": "select_querystring_field"
},
"hidden": {
"title": "Hide facet?",
"type": "boolean",
"default": false
}
}
}
},
"toggleFacet": {
"blockSchema": {
"properties": {
"title": {
"title": "Label"
},
"field": {
"title": "Field",
"widget": "select_querystring_field"
},
"hidden": {
"title": "Hide facet?",
"type": "boolean",
"default": false
}
}
}
}
}JSON Block Data
Example JSON as stored in the Plone content API. This is the data structure your component will receive in the block prop.
{
"@type": "search",
"facetsTitle": "Filter by",
"facets": [
{
"@id": "facet-1",
"type": "checkboxFacet",
"title": "Content Type",
"field": "portal_type",
"multiple": true,
"hidden": false
},
{
"@id": "facet-2",
"type": "daterangeFacet",
"title": "Date Range",
"field": "effective",
"hidden": false
}
],
"blocks": {
"listing-1": {
"@type": "listing",
"variation": "summary",
"querystring": {
"query": [
{
"i": "portal_type",
"o": "plone.app.querystring.operation.selection.any",
"v": [
"Document",
"News Item"
]
}
]
}
}
},
"listing": {
"items": [
"listing-1"
]
}
}Component
Render component for your frontend framework. Add this to your block renderer's switch/map so it handles this @type.
function SearchBlock({ block, blockId }) {
const [query, setQuery] = useState('');
const facets = (block.facets || []).filter(f => !f.hidden);
const listing = block.listing || {};
const listingId = listing.items?.[0];
const listingBlock = listingId ? (block.blocks?.[listingId]) : null;
return (
<div data-block-uid={blockId} className="search-block">
<input
type="search"
placeholder="Search..."
value={query}
onChange={e => setQuery(e.target.value)}
/>
{facets.length > 0 && (
<div className="facets">
<h4>{block.facetsTitle || 'Filter'}</h4>
{facets.map(facet => (
<FacetRenderer key={facet['@id']} facet={facet} />
))}
</div>
)}
{listingBlock && (
<ListingBlock block={listingBlock} blockId={listingId} />
)}
</div>
);
}
function FacetRenderer({ facet }) {
switch (facet.type) {
case 'checkboxFacet':
return <fieldset data-block-uid={facet['@id']}><legend data-edit-text="title">{facet.title}</legend>{/* checkbox options */}</fieldset>;
case 'selectFacet':
return <label data-block-uid={facet['@id']}><span data-edit-text="title">{facet.title}</span><select>{/* options */}</select></label>;
case 'daterangeFacet':
return <label data-block-uid={facet['@id']}><span data-edit-text="title">{facet.title}</span><input type="date" /> – <input type="date" /></label>;
case 'toggleFacet':
return <label data-block-uid={facet['@id']}><input type="checkbox" /> <span data-edit-text="title">{facet.title}</span></label>;
default:
return null;
}
}