# Text match

> Search that ignores case and diacritics, ranks the best matches first and returns the ranges to highlight.

- Type: React helper (Hooks & Utilities)
- Access: Free (the source is open to everyone)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add text-match`
- Docs: https://wingo-ui.com/components/text-match

## Interaction

Type in the field: zurich finds Zürich, sao paulo finds São Paulo, and every word of the query has to match somewhere. The best matches rise to the top and the matched letters are highlighted. Turn on fuzzy to let letters in order with gaps match too (dsdf finds Düsseldorf).

## Installation

```bash
npx wingo-ui@latest add text-match
```

The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add https://wingo-ui.com/r/text-match.json`

Files:

- `lib/text-match.ts`

## Usage

```tsx
import { filterByText, splitByRanges } from "@/lib/text-match"

const cities = ["Zürich", "São Paulo", "Kraków", "Montréal", "Düsseldorf"]

export function CityResults({ query }: { query: string }) {
  const results = filterByText(cities, query, (city) => city)
  return (
    <ul>
      {results.map(({ item, ranges }) => (
        <li key={item}>
          {splitByRanges(item, ranges).map((part, i) =>
            part.match ? <strong key={i}>{part.text}</strong> : <span key={i}>{part.text}</span>,
          )}
        </li>
      ))}
    </ul>
  )
}
```

## API

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `query?` | `string` | `""` | The demo's search text. Case and diacritics never matter; each word must match (in any order). |
| `fuzzy?` | `boolean` | `false` | MatchOptions.fuzzy: also accept the query's letters in order with gaps, scored lowest. Good for short lists of known names; leave it off for long lists, where it lets too much through. |
| `filterByText?` | `<T>(items: readonly T[], query: string, getText: (item: T) => string \| readonly string[], options?: { fuzzy?: boolean; limit?: number }) => { item: T; score: number; ranges: MatchRange[] }[]` |  | The matching items, best first and stable for ties. getText returns the label, or [label, ...keywords]: keywords (a country's calling code, an English name) can match too, a little lower, and ranges always refer to the label. An empty query returns every item in order. |

## Parts

### matchText (function)

One text against a query, or null when a word is missing. Scores: exact 1, whole-text prefix 0.9, word prefix 0.75, inside a word 0.5, fuzzy 0.25, averaged over the query's words, with a small bonus for shorter texts. Signature: (text: string, query: string, options?: { fuzzy?: boolean }) => { score: number; ranges: MatchRange[] } | null.

### splitByRanges (function)

Cuts a label into plain and matched pieces for rendering, e.g. matched pieces in font-semibold. Signature: (text: string, ranges: readonly MatchRange[]) => { text: string; match: boolean }[].

### normalizeText (function)

Lowercase, without diacritics (é, ü, ñ, ø, the Romanian comma and cedilla s / t and friends), whitespace collapsed. Use it for keys and exact comparisons. Signature: (text: string) => string.

### compareText (function)

A cached Intl.Collator compare for sorting labels the way the locale's dictionary does, numbers in natural order. Signature: (a: string, b: string, locale?: string) => number.

## Examples

- **People search with keywords**: Email and team are keywords: "northwind" finds everyone with a northwind.example address. Type a name to see its match highlighted.
- **Sorting labels**: compareText sorts accented names where a reader expects them; a plain sort pushes them to the end.

## See also

- [useDebounce](https://wingo-ui.com/components/use-debounce) ([Markdown](https://wingo-ui.com/components/use-debounce.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))
- [Date utils](https://wingo-ui.com/components/date-utils) ([Markdown](https://wingo-ui.com/components/date-utils.md))

---

Canonical: https://wingo-ui.com/components/text-match
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
