SearchCombobox

Hakukenttä

Ehdottaa kirjoittaessa; kuori ilman datakerrosta.

Käyttöpaikat

Suoraan: palvelu tuo osan itse. Välillisesti: osa tulee mukaan toisen paketin osan kautta, ja sen muutos näkyy palvelussa silti. Laskettu julkaisun yhteydessä 23.10.2026.

TP-PERUSTUS
TP-IAM · HEADER_SEARCH_INPUTin kautta
TP-TTK · HEADER_SEARCH_INPUTin kautta
TP-VASTAANOTTO · HEADER_SEARCH_INPUTin kautta
Esimerkki valitulla teemalla ja sävyllä; vaihda ne yläpalkista.

Käyttö

Paketin README:n luku sellaisenaan.

SearchCombobox — haku ehdottaa kirjoittaessa

<SearchCombobox
  search={async (q, signal) => {
    const res = await fetch(`/api/haku?q=${encodeURIComponent(q)}`, { signal });
    return osumat(await res.json()); // litteä lista ryhmäjärjestyksessä
  }}
  hitKey={(o) => o.href}
  group={(o) => o.ryhma}
  renderHit={(o) => (
    <>
      <ToimittajaIkoni … />
      <div className="min-w-0 flex-1">
        <div className="truncate">{o.otsikko}</div>
        <div className="truncate text-xs text-muted-foreground">{o.selite}</div>
      </div>
    </>
  )}
  onOpen={(o) => router.push(o.href)}
  onDefault={(q) => router.push(`/tuotteet?haku=${encodeURIComponent(q)}`)}
  footer={({ query, close }) => (
    <Link href={…} onClick={close} className="block border-t px-3 py-2 text-sm text-muted-foreground">
      Kaikki tuotteet haulla "{query}" ↵
    </Link>
  )}
  placeholder="Hae toimittajia, käsittelyjä tai tuotteita"
/>

Kuori omistaa ajastuksen ja vanhentuneen vastauksen hylkäyksen, kuluttaja omistaa datan. search kutsutaan vasta kun syöte on vähintään minChars (2) merkkiä ja pysynyt paikallaan delayMs (200 ms); vastaus jonka järjestysnumero ei ole uusin hylätään, ja edellinen pyyntö keskeytetään signalilla. Nuolet valitsevat (nextSelection, viety myös @karkkainen/ui/lib/searchista), Enter avaa valitun tai kutsuu onDefaultia, Esc ja klikkaus ulkopuolelle sulkevat.

> Valinta rivillä on `onMouseDown`, ei `onClick`. Kentän blur ehtii > muuten sulkea listan ennen klikkausta. Ja valtuutus on hakureitin > asia, ei kuoren: jos osumien näkyvyys riippuu käyttäjästä, suodata > ryhmä kerrallaan reitissä ja palauta kyvytön ryhmä tyhjänä, ei 403:lla.

Ikonilinjaus riveillä (TP-Perustus 13.10.2026): tunnistava ikoni — esim. toimittajan lyhenne ja väri — vain kun rivin kohde on se entiteetti; muilla riveillä lajin kuvake samassa 32 px paikassa, muuten ikoni ei tunnista mitään. Raskaat lisätiedot (kuvat) haetaan onResultsin jälkeen omalla viiveellään, ei haun vastauksessa.

Puhelimella kuori kääritään Sheetiin (side="top"); se ei ole osa komponenttia.

Tuonti ja lähde

import { SearchCombobox, SearchComboboxPanel } from "@karkkainen/ui";
  • src/components/search-combobox.tsx