Search

Simple Search

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.

Search with Facets

Filter by

Content Type
Tags

Grid-Text block

The Grid block allows adding multi-column blocks. A grid block can contain between one and four columns of different blocks. Text, teasers, images and videos can be added in a grid block.

Grid-Teaser block

The Grid block allows adding multi-column blocks. A grid block can contain between one and four columns of different blocks. Text, teasers, images and videos can be added in a grid block.

Grid-Listing

The Grid block allows adding multi-column blocks. A grid block can contain between one and four columns of different blocks. This is a grid block with multiple listing blocks.

Grid-image block

The Grid block allows adding multi-column blocks. A grid block can contain between one and four columns of different blocks. Text, teasers, images and videos can be added in a grid block.

Grid

The Grid block allows adding multi-column blocks. A grid block can contain between one and four columns of different blocks. Teasers and images can be added in a grid block.

Button

The button block shows a button for which a link (internal or external) can be stored. The button can be displayed left, right or center and have a background color.


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;
  }
}