# `hb-searchbar` (searchbar)

**Category:** utilities  
**Tags:** utilities, search  
**Package:** `@htmlbricks/hb-searchbar`

## Overview

`hb-searchbar` is a Bulma-styled search control that lives in a shadow root. It renders either a single-line `<input type="search">` or a multiline `<textarea>`, an in-field submit (magnifier) button, and an optional suggestion dropdown driven by a `searchlist` you pass in.

Use it when you want a self-contained query field with debounced “search while typing”, optional fixed or fuzzy-matched suggestions, rich rows (icons, badges, tags, links), and explicit `search` / `clear` custom events for your host application.

## Custom element

```html
<hb-searchbar …></hb-searchbar>
```

## Attributes and properties

Web component attributes are **strings**. For structured data (`searchlist`, `input_info`), pass **JSON** as a string attribute (or set the corresponding property with a parsed object in JavaScript). Boolean-like flags use **`yes`** / **`no`** where noted.

| Name | Required | Description |
|------|----------|-------------|
| `value` | Yes | Current query text. |
| `id` | No | Host id string; included on `clear` event detail. |
| `style` | No | Inline style string for the host (optional). |
| `searchlabel` | No | Placeholder text. Default: `"Search"`. |
| `minlength` | No | Minimum query length (number) before input-driven search runs and before the preview can open; default `0`. Compares `value.length` to this number. |
| `searchlist` | No | Array of suggestions (`TSearchListItem[]`). From HTML, use a JSON string. Parsed at runtime if a string is received. |
| `input_info` | No | Single `TSearchListItem` shown when its `text` equals the current `value` (JSON string from HTML). |
| `textarea` | No | Multiline mode: `"yes"`, `"true"`, or `""` (empty string) enables `<textarea>`; otherwise a search `<input>` is used. |
| `disable_preview` | No | When `"yes"`, `"true"`, or `"on"`, the suggestion dropdown does not open. Any other value (including `"no"`, `"false"`, `"off"`) allows preview when other conditions are met. |
| `disabled` | No | `"yes"` disables the field and action buttons; `"no"` or omitted leaves them enabled. |

### `TSearchListItem` shape

Each suggestion (and `input_info`) uses:

| Field | Type | Notes |
|-------|------|--------|
| `id` | string | Required stable id for the row. |
| `text` | string | Primary label. |
| `url` | string | Optional link target for the row. |
| `icon` | string | Optional Bootstrap Icons icon name (without `bi-` prefix in markup; the component uses `bi bi-{icon}` classes). |
| `number_of_results` | number | Optional count display. |
| `fixed` | boolean | When `true`, the row stays visible regardless of the current filter. |
| `tags` | `TSearchListItemTag[]` | Optional chips: `text`, `color`, `icon`. |
| `badge` | `TSearchListItemBadge` | Optional badge: `text`, `color`, `icon`. |

Tags and badges use Bulma-style color names (for example `primary`, `success`, `danger`) as consumed by the row renderer.

### How the suggestion list behaves

- **Filtering:** Non-fixed items are shown when their `text` contains the current `value` (case-insensitive substring match). Items with `fixed: true` are always included.
- **Opening:** The dropdown is shown when preview is not disabled, the query length is **greater than** `minlength`, and the field is considered “open” after interaction (typing opens it; choosing an action may close it depending on the trigger).
- **Debounced input search:** After input changes, a **500 ms** debounce runs; if the value is non-empty and satisfies `minlength`, a `search` event fires with `by: "input"`. Enter in the field triggers submit-style search (`by: "button"`) without waiting for the timer.
- **Submit button:** Clicks dispatch `search` with `by: "button"`.
- **Picking a suggestion:** Dispatches `search` with `by: "searchlist"` and updates the field text to the chosen item’s `text`.
- **Clearing:** For the native search input, clearing via the browser’s search clear control dispatches `clear` with `{ id }`. In textarea mode, an explicit clear button empties the value, dispatches `clear`, and closes the dropdown. Clicks outside the host close the dropdown without clearing the value.

## Events

Listen with `addEventListener` on the host element.

| Event | Detail (TypeScript `Events`) |
|-------|-------------------------------|
| `search` | `{ input: string; by: "button" \| "input" \| "searchlist"; item?: TSearchListItem }` — when the user picks a suggestion, **`item`** is the matched list entry; for **`by: "input"`** or **`"button"`**, **`item`** is omitted. |
| `clear` | `{ id: string }` — the host **`id`** attribute (empty string if unset). |

## Styling

### Bulma CSS variables

The component uses Bulma layout and form patterns inside the shadow tree. Theme it with **`--bulma-*`** variables on a wrapping scope or `:root` / `body` so they apply to `:host`. Relevant groups include:

- **Accent and focus:** `--bulma-primary`, `--bulma-danger`
- **Surfaces and chrome:** `--bulma-background`, `--bulma-scheme-main`, `--bulma-border`, `--bulma-border-weak`
- **Typography:** `--bulma-text`, `--bulma-text-strong`, `--bulma-input-placeholder-color`
- **Shape and stacking:** `--bulma-radius`, `--bulma-radius-small`, `--bulma-dropdown-content-z`

See [Bulma CSS variables](https://bulma.io/documentation/features/css-variables/) for the full variable system.

### Component-specific variables (`--hb-searchbar-*`)

These override frosted layers and panel backgrounds (defaults use `color-mix()` with Bulma tokens):

- `--hb-searchbar-host-background` — host background at rest  
- `--hb-searchbar-host-background-focus` — host background while focused  
- `--hb-searchbar-input-strip-background` — input row strip  
- `--hb-searchbar-dropdown-panel-background` — open suggestion panel  
- `--hb-searchbar-input-glass-blur` — backdrop blur behind the focused field  
- `--hb-searchbar-input-glass-saturate` — backdrop saturation factor  

Authoritative descriptions and defaults are listed in `extra/docs.ts` (`styleSetup.vars`).

### CSS shadow parts

| Part | Targets |
|------|---------|
| `dropdown-menu` | Open suggestion list panel |
| `search-input` | Native `<input>` or `<textarea>` |
| `search-input-glass` | Frosted layer behind the field while focused |
| `search-submit` | In-field magnifier / submit control |

Example:

```css
hb-searchbar::part(search-submit) {
  color: var(--bulma-primary);
}
```

## Icons and assets

The component loads **Bootstrap Icons** from jsDelivr in the shadow document head (`bootstrap-icons.css`). Icon names in `searchlist` / `input_info` refer to that font set.

## Slots

None (`htmlSlots` is empty).

## Usage notes

- **Autocomplete:** The control sets `autocomplete="off"`. Browsers may still offer their own UI; behavior varies.
- **Storybook:** Controls may expose names like `initial_value` for demos; the runtime contract for authors is `types/webcomponent.type.d.ts` (`value` is the live bound field).
- **Structured props from HTML:** Always serialize `searchlist` and `input_info` as JSON strings on attributes; never rely on passing raw objects through HTML attributes.

## Examples

### Minimal search field

```html
<hb-searchbar
  value=""
  searchlabel="Search"
></hb-searchbar>
```

### Suggestions with JSON `searchlist`

```html
<hb-searchbar
  value=""
  searchlabel="Try a suggestion"
  searchlist='[{"id":"1","text":"Documentation"},{"id":"2","text":"API reference"}]'
></hb-searchbar>
```

### Multiline textarea mode

```html
<hb-searchbar
  value=""
  searchlabel="Describe your query"
  textarea="yes"
  searchlist='[{"id":"1","text":"Example prompt"}]'
></hb-searchbar>
```

### Disable preview, require two characters before input search

```html
<hb-searchbar
  value=""
  disable_preview="yes"
  minlength="2"
></hb-searchbar>
```

### JavaScript: listen for `search` and `clear`

```javascript
const el = document.querySelector("hb-searchbar");

el.addEventListener("search", (e) => {
  const { input, by } = e.detail;
  console.log("search", { input, by });
});

el.addEventListener("clear", (e) => {
  console.log("cleared", e.detail.id);
});
```

## License

Package metadata references **Apache-2.0** (see `LICENSE.md` in the published package when consuming from npm).
