Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to highlight text in para using array of values?

I have array of values

const tags = ['Hello', 'moment', 'somewhere'];

and the paragraphs to show in my react component

const paras = [{
  text: 'Hello, tina. Thank you for all waiting. Hello?'
}, {
  text: 'When can I go? Okay. One moment. Let me just'
}, {
  text: 'if I can help you somewhere, if you are interested'
}]

enter image description here

I want to highlight the para words with the tags element. And also only need few words before and after highlighted words like in the first sentence I only need to show like

 *One **moment**. Let *

How can I do that?

What I have tried:

getHighlightedText(text, highlight) {
    // Split text on highlight term, include term itself into parts, ignore case
    const parts = text.split(new RegExp(`(${highlight})`, 'gi'));
    return <span>{parts.map(part => part.toLowerCase() === highlight.toLowerCase() ? <span className="highlight">{part}</span> : part)}</span>;
  }

{
  paras.map((para) => {
    return (
      <Row key={para._id}>
        <Col md={11}>
          <div className="record">
            <p className="mb-0">
              {this.getHighlightedText(para.text, "hello")}
            </p>
          </div>
        </Col>
        <Col md={1}>
          <Button className="buttonLink" color="link">
            <b>{"View >"}</b>
          </Button>
        </Col>
      </Row>
    );
  });
}
like image 851
Profer Avatar asked Dec 30 '25 17:12

Profer


1 Answers

Here is a super simple to use reusable component for text highlighting by tags:

function Highlight({ children: text = "", tags = [] }) {
  if (!tags?.length) return text;
  const matches = [...text.matchAll(new RegExp(tags.join("|"), "ig"))];
  const startText = text.slice(0, matches[0]?.index);
  return (
    <span>
      {startText}
      {matches.map((match, i) => {
        const startIndex = match.index;
        const currentText = match[0];
        const endIndex = startIndex + currentText.length;
        const nextIndex = matches[i + 1]?.index;
        const untilNextText = text.slice(endIndex, nextIndex);
        return (
          <span key={i}>
            <mark>{currentText}</mark>
            {untilNextText}
          </span>
        );
      })}
    </span>
  );
}

export default function App() {
  return (
    <div className="App">
      <h1>
        <Highlight tags={["Hel", "co", "nd"]}>Hello CodeSandbox</Highlight>
      </h1>
      <h2>
        <Highlight tags={["ditin", "e"]}>
          Start editing to see some magic happen!
        </Highlight>
      </h2>
    </div>
  );
}

Demo in Codesndbox

example code output

Using it with your example:

const tags = ["Hello", "moment", "somewhere"];
const paras = [
  {
    text: "Hello, tina. Thank you for all waiting. Hello?"
  },
  {
    text: "When can I go? Okay. One moment. Let me just"
  },
  {
    text: "if I can help you somewhere, if you are interested"
  }
];
function ParasList() {
  return (
    <ul>
      {paras.map((para, i) => (
        <li key={i}>
          <Highlight tags={tags}>{para.text}</Highlight>
        </li>
      ))}
    </ul>
  );
}

example code #2 output

Explanation:

The Highlight component is easy to use, you just wrap around some text, and put on the "tags" attribute: <Highlight tags={["some"]}>some text</Highlight>

Inside the component, I'm using the new and shiny string.prototype.matchAll function, which gives us information about the match and the index where it was found.

Also, I'm creating the regex using join("|") on the tags, so they have an "OR" relationship between them. The flag i makes the highlight case insensitive, but you could delete it if you would want to keep case sensitivity. The g flag is the global flag, so duplicate matches are found and highlighted. It is required in a matchAll search.

Lastly, I'm using the <mark> html tags for highlighting, but you could easily change this, or even pass a custom tag through props for more versatility. You could also just enclose the "marked" bits with a regular span, and mark them with a "highlighted" className, and customize the appearance that way, using CSS.

like image 122
deckele Avatar answered Jan 02 '26 07:01

deckele



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!