Skip to content

Highlight

Marks the parts of a text that match a search query. Use it to show what matched in a list of search results or a filtered list.

tsx
import { Highlight } from 'neba';

<Highlight query="acrylic">A sheet of cut acrylic.</Highlight>
<Highlight query={['data', 'database']} variant="text" color="primary">…</Highlight>
<Highlight query={/\d+/} caseSensitive>…</Highlight>;

Props

PropTypeDefaultDescription
query * string | string[] | RegExpWhat to find. An array tries the longest term first, so `database` wins over `data`. A RegExp is used as written with the global flag forced on, and then caseSensitive and wholeWord are ignored
variantshared'solid' | 'outline' | 'text''solid'Weight of the mark: `solid` is the highlighter pen, `outline` a hairline box around the word, `text` the colour alone
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''warning'Semantic colour role. `warning` by default and not arbitrarily: it is the one family whose fill is light with dark ink, so a solid mark is a yellow highlighter over black text
caseSensitivebooleanfalseWhether `a` and `A` are different letters
wholeWordbooleanfalseWhether a term has to be a word on its own: `cat` marking "cat" but not "concatenate". A word is a run of letters, digits and underscores in any script, which means very little for text that is not delimited by spaces
underlinebooleanfalseUnderlines the mark as well. Combines with every variant
weight'regular' | 'medium' | 'semibold' | 'bold'Weight of the mark. Omit it and it is the weight of the text around it: the surface already says "this one", and a bolded word changes the rhythm of the whole line
childrenReactNodeThe text to search. Elements are walked into, so a match inside a `<strong>` is marked and the `<strong>` survives

Pass whatever the search box holds straight into query: a string, an array of strings, or a regular expression. There is no need to pre-compute match offsets. The component holds no state, so the marks update when children or query changes.

There is no size: a mark sits inside running text and takes the surrounding type size.

Examples

variant · underline · weight

variant is the weight of the mark. solid fills it like a highlighter pen, outline draws a hairline around the word, text changes the colour alone. underline and weight are separate axes that combine with all three.

color defaults to warning, the one family whose fill is light with dark ink on it, so solid reads as a yellow highlighter. Any other family becomes white text on a block of colour.

caseSensitive and wholeWord

caseSensitive respects case; wholeWord matches only at word boundaries. A word here is a run of letters, digits and underscores, so it does very little for Korean or Japanese, where phrases are not delimited by spaces: which is why it is off by default.

An array of strings is tried longest first: matching ['data', 'database'] shortest-first would mark data and leave base outside the mark.

Text inside nested elements

children does not have to be a string. The React tree is walked into: text nodes are marked and every other element is left exactly as it was.

Accessibility

  • Marks render as real <mark> elements, which carry the meaning "text of relevance to the reader". Marking too many words in one paragraph dilutes that meaning.
  • A <mark> arrives from the browser's own stylesheet with a yellow background, which is why variant="text" sets background to transparent explicitly.

Released under the MIT License