# Search

> A search field with a magnifying glass. A CSS component with two classes and no JavaScript.

An `lt-input` with room for a magnifying glass. Both classes are set, so every state and variable from [Input](/components/input.md) applies here too.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/search/search.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/button/button.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/label/label.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/sr-only/sr-only.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<form class="lt-search-row" role="search">
<label class="lt-label lt-sr-only" for="search">Search cases</label>
<input class="lt-input lt-search" type="search" id="search" name="q" placeholder="Search cases" />
<button class="lt-button" type="submit">Search</button>
</form>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/search.css"
import "@lo-tek/interfaces/button.css"
import "@lo-tek/interfaces/label.css"
import "@lo-tek/interfaces/sr-only.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<form className={lt.search.row} role="search">
  <label {...lt.label()} htmlFor="search">Search cases</label>
  <input {...lt.search()} id="search" />
</form>
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If the element is already there,** set them on it. That is the way when you enhance HTML a server or a template has sent:

```ts
import { lt } from "@lo-tek/interfaces"


const field = document.querySelector<HTMLInputElement>("#search")


lt.setAttributes(field, lt.search())
```

`lt.search()` sets both `lt-input` and `lt-search`, and `type="search"`. `lt.search.row` gives the class for the row with the field and the button.

`type="search"` gives the browser’s own cross for clearing the field, and “Search” instead of “Enter” on the mobile keyboard. Safari and Chrome draw the cross differently, Firefox does not draw it at all, and whether Escape clears the field varies.

`role="search"` on the form lets screen readers jump straight to the search on the page.

## The label cannot be dropped

The placeholder disappears as soon as the user types, and several screen readers do not read it out. If the field is so obviously a search that a visible label becomes noise, hide it with [`.lt-sr-only`](/components/sr-only.md) rather than leaving it out.

## Searching as the user types

```html
<label class="lt-label lt-sr-only" for="search">Search the cases</label>
<input class="lt-input lt-search" type="search" id="search" name="q" />
<p class="lt-sr-only" role="status" id="matches"></p>


<script type="module">
  const field = document.getElementById("search")
  const status = document.getElementById("matches")
  let timeout


  field.addEventListener("input", () => {
    clearTimeout(timeout)
    timeout = setTimeout(async () => {
      const response = await fetch(`/api/search?q=${encodeURIComponent(field.value)}`)
      const cases = await response.json()


      renderResults(cases)
      status.textContent = `${cases.length} matches`
    }, 300)
  })
</script>
```

The 300 millisecond delay is not only for the server. Without it the number of matches is read out on every keystroke.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-search` | The search field. Used together with `.lt-input`. |
| `.lt-search-row` | The row with the field and the button |

| Variable | Default |
| - | - |
| `--lt-search-icon-space` | `var(--lt-spacing-10)` |
| `--lt-search-icon-size` | `var(--lt-spacing-5)` |

The icon comes from `--lt-icon-search` and follows the theme. See [Customising](/customising.md).

## Accessibility

- Announce the number of matches in an element with `role="status"`. Without it, someone listening to the page does not know whether the search found anything.
- Do not remove the browser’s cross without offering something else. Clearing the field by hand is awkward on a phone.
- If search is the main function of the page, let the field have focus from the start. If it is one of several tools, do not: focus that jumps is confusing.
