Creating react-highlighter component
If you were creating your own autocomplete in jQuery, React or any other library/framework you probably wanted to highlight some letters of each item that matches user search criteria something like this:
In this article I will explain idea, and also solution that has only few lines of code. When I tried to do this few years ago it took me more than 150 lines of code. Here I will explain how to create it using React and TypeScript.
If you want to do this only by CSS, well, it is not possible. Idea is to take text of some item and split it into multiple HTML tags and apply CSS class only to certain HTML elements.
If original item was
<span>Makarska - center</span>
and user types in kar newly created html would look like this:
<div class="d-inline"> <span class="">Ma</span> <span class="bold">kar</span> <span class="">ska - center</span></div>
If you know how JavaScript split
function works you know that will not help in creating most elegant solution if you send to it just string delimiter. Problem is that when you try to split some string by another string it will not keep the separator.
Check this example:
var str = "How are you doing today?"; var res = str.split("o");
The result of res will be an array with the values:
H,w are y,u d,ing t,day? This is definition of Split function
str.split([separator[, limit]])
Parameters
separator
Optional
- Specifies the string which denotes the points at which each split should occur. The
separator
is treated as a string or as a regular expression. If a plain-textseparator
contains more than one character, that entire string must be found to represent a split point. Ifseparator
is omitted or does not occur instr
, the array returned contains one element consisting of the entire string. Ifseparator
is an empty string,str
is converted to an array of characters.
So javascipt split
function can receive regular expression with specified search term. This is what I inially tried:
var splitPattern = this.props.searchTerm != null ? new RegExp( this.props.searchTerm , "i") : ''; var miniWords = name.split(splitPattern);
There were few problems. First I didn’t put search term in capturing group so I get same effect if I do:
var miniWords = name.split(this.props.searchTerm);
Other problem is that I needed a way to ignore casing. Luckily RegExp as second parameter accepts flag “i” that basicly means ignore casing.
Combining those two this is I came up with:
var splitPattern = this.props.searchTerm != null ? new RegExp("(" + this.props.searchTerm , "i") : ''; var miniWords = name.split(splitPattern);
This is whole render function of the component:
import * as React from 'react' export default class HighLighter extends React.Component<IHighLighterProps, IHighLighterState>{ constructor(props: IHighLighterProps) { super(props); } renderName(name: string) { var splitPattern = this.props.searchTerm != null ? new RegExp("(" + this.props.searchTerm , "i") : ''; var miniWords = name.split(splitPattern); var html = []; _.each(miniWords, (miniWord, index) => { if (this.props.searchTerm != null && miniWord.toLowerCase() == this.props.searchTerm.toLowerCase()) { html.push(<span className={this.props.highlightedItemClass}>{miniWord}</span>) } else { html.push(<span className={this.props.itemClass}>{miniWord}</span>) } }); return <span> {html}</span>; } render() { const { wrapperClass } = this.props; return ( <div className={wrapperClass}>{this.renderName(this.props.text)}</div> ) } } interface IHighLighterProps { searchTerm: string; text: string; wrapperClass: string; highlightedItemClass: string; itemClass: string; } interface IHighLighterState { }
Mit.edu
Amazing! Its really remarkable article, I have got much clear idea
about from this post.