
# Search Components

Where tables declare _what_ is searchable and engines declare _how_ a query runs (see [search-overview](/en/docs/search-overview)), components are _where_ search appears on the page. Sovrium provides five complementary pieces: a `searchInput` that drives a query, a `list` that renders results, a `pageSearch` that indexes static page content, a `command` palette for keyboard-driven navigation, and toolbar search built into data components.

| Component        | Purpose                                                                        |
| ---------------- | ------------------------------------------------------------------------------ |
| `searchInput`    | Standalone search box that drives another component via `dataSource.bindTo`.   |
| `list`           | Search-first result display with item templates, highlighting, and pagination. |
| `pageSearch`     | Site-wide static search over public page content (build/start-time index).     |
| `command`        | Command palette (⌘K-style) for grouped, keyboard-driven actions.               |
| toolbar `search` | In-component search bar on `data-table`, kanban, calendar, etc.                |

## `searchInput`

A standalone search box. On its own it renders an accessible input; bound to a data source it becomes the query driver for a sibling component. Pair it with a `list` (or `data-table`) whose data source sets `bindTo` to the input's `id`.

| Property     | Description                                                            |
| ------------ | ---------------------------------------------------------------------- |
| `id`         | Identifier other components reference via `dataSource.bindTo`.         |
| `visibility` | Standard visibility controls (shared across components).               |
| `i18n`       | Standard internationalization fields (translatable label/placeholder). |

```yaml
components:
  # 1. The input drives the query
  - type: searchInput
    id: product-query

  # 2. The list consumes it via bindTo
  - type: list
    dataSource:
      table: products
      mode: search
      searchFields: [name, description]
      searchEngine: hybrid
      debounceMs: 300
      bindTo: product-query
    listDisplay:
      itemTemplate:
        title: '$record.name'
        subtitle: '$record.description'
      highlight: true
```

:::callout
`debounceMs` lives on the **data source** of the consuming component, not on `searchInput` — the input emits keystrokes and the bound data source debounces them before querying. See [search-overview](/en/docs/search-overview#the-search-data-source-mode).
:::

## `list` — result display

The `list` component is designed as a search-first display: the natural companion for `searchInput`. It renders each record through an item template with optional highlighting, dividers, and load-more pagination.

| Property                | Description                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `itemTemplate.title`    | Primary text via a `$record.*` reference (e.g. `$record.name`).                                                     |
| `itemTemplate.subtitle` | Secondary text (e.g. `$record.description`).                                                                        |
| `itemTemplate.image`    | Image URL (e.g. `$record.thumbnail`).                                                                               |
| `itemTemplate.badge`    | Badge text (e.g. `$record.category`).                                                                               |
| `itemTemplate.metadata` | Array of `{ field, format }` shown in the item footer (`currency`, `relative-date`, `badge`, `text`, `short-date`). |
| `emptyMessage`          | Message shown when no results match.                                                                                |
| `loadMore`              | `button` (Load More button) or `infinite` (load on scroll).                                                         |
| `highlight`             | Boolean. Highlight matched search terms in item text (default `false`).                                             |
| `divider`               | Boolean. Show visual dividers between items (default `false`).                                                      |
| `maxItems`              | Maximum number of items to display (integer ≥ 1).                                                                   |

```yaml
- type: list
  dataSource:
    table: products
    mode: search
    searchFields: [name, description]
    bindTo: product-query
  listDisplay:
    itemTemplate:
      title: '$record.name'
      subtitle: '$record.description'
      image: '$record.thumbnail'
      badge: '$record.category'
      metadata:
        - field: price
          format: currency
    emptyMessage: No products found
    loadMore: infinite
    highlight: true
    divider: true
    maxItems: 50
```

## `pageSearch` — static page index

A site-wide search component that indexes **public pages** (`access` missing or `access: 'all'`) at `sovrium build` time and `sovrium start` boot. The index is a JSON file plus a tiny client runtime under `<outputDir>/sovrium-search/`, served by the public-dir route. This is a different layer from record search — it searches page _content_, not table rows.

| Property      | Description                                              |
| ------------- | -------------------------------------------------------- |
| `placeholder` | Placeholder text shown in the search input.              |
| `maxResults`  | Maximum number of results to display (positive integer). |
| `visibility`  | Standard visibility controls.                            |
| `i18n`        | Standard internationalization fields.                    |

```yaml
pages:
  - id: home
    name: home
    path: /
    components:
      - type: pageSearch
        placeholder: Search the site...
        maxResults: 10
```

:::callout
`pageSearch` is **self-activating**: the moment a `type: 'pageSearch'` component appears anywhere in `app.pages[].components[]`, `sovrium build` and `sovrium start` emit the static search index. No env var, no top-level `app.search` config. The indexer crawls public pages only — pages with `access: 'authenticated'`, role arrays, or `require`-based access are excluded from the index.
:::

## `command` — command palette

A ⌘K-style command palette for keyboard-driven navigation and actions. Commands are organized into groups, each surfacing searchable entries the user filters by typing.

| Property        | Description                                           |
| --------------- | ----------------------------------------------------- |
| `commandGroups` | Array (≥ 1) of grouped commands shown in the palette. |
| `visibility`    | Standard visibility controls.                         |
| `i18n`          | Standard internationalization fields.                 |

```yaml
- type: command
  commandGroups:
    - heading: Navigation
      commands:
        - label: Go to Dashboard
          href: /dashboard
        - label: Go to Settings
          href: /settings
    - heading: Actions
      commands:
        - label: New Product
          href: /products/new
```

## Toolbar search

Data components expose an in-component search bar through their toolbar. On a `data-table`, set `toolbar.search: true` to render a global search input over the bound rows — a quick filter without a separate `searchInput`.

| Toolbar flag | Description                   |
| ------------ | ----------------------------- |
| `search`     | Show the global search input. |
| `filters`    | Show the filter builder.      |
| `sort`       | Show the sort builder.        |

```yaml
- type: data-table
  dataSource:
    table: orders
    mode: search
    searchFields: [customer, reference]
  toolbar:
    search: true
    filters: true
    sort: true
```

Kanban and calendar components share a `search` configuration for their own in-component search bar via the same pattern.

## Highlighting and debounce

- **Highlighting** — set `highlight: true` on `list` (`listDisplay.highlight`) to wrap matched terms in result text. Off by default.
- **Debounce** — set `debounceMs` on the data source (e.g. `300`) so the query fires only after the user pauses typing, preventing a request per keystroke.

These work together: a `searchInput` emits keystrokes, the bound data source debounces and queries, and the `list` highlights matches in the rendered results.

## Related

- [Search Overview](/en/docs/search-overview) — engines and the `search` data-source mode.
- [Full-Text Search](/en/docs/full-text-search) — field `indexed`, `searchWeight`, and `fullTextSearch`.
- [Data Components](/en/docs/data-components) — `data-table`, kanban, calendar, and their toolbars.
- [Content Components](/en/docs/content-components) — text, media, and structural page content.
- [Records: Filtering & Sorting](/en/docs/records-filtering-sorting) — non-search list filtering and ordering.
