Reputation: 75
How can i surround certain letters in a string by an html tag?
For example, given this string: Sgt. Pepper's Lonely Hearts Club Band
and this substring: Pepp
. I want to surround the substring inside the string with an html tag. Like this: Sgt. <mark class="Search-suggestions-match">Pepp</mark>er's Lonely Hearts Club Band
.
I achieved this, but React is escaping the span tags. But also, i don't know if i should take another approach, maybe a more JSX one.
This is the component where im trying to implement it:
class SearchSuggestions extends Component {
constructor(props) {
super(props)
if (!this.props.suggestions || !this.props.term) {
return
}
this.state = {
suggestions : this.props.suggestions.map(item => this.markText(item))
}
}
markText(string) {
return string.replace(new RegExp(this.props.term, "ig"), match => {
return `<mark class="Search-suggestions-match">${match}</mark>`
})
}
render() {
if (!this.props.suggestions || !this.props.term) {
return null
}
return (
<ul className="Search-suggestions-component">
{this.state.suggestions.map((value, i) => <li key={i}>{value}</li>)}
</ul>
)
}
}
Upvotes: 2
Views: 7765
Reputation: 11581
Use a regular expression to split the string, capturing the desired match, and then format it with JSX:
markText(string) {
let strArr = string.split(new RegExp(`(${this.props.term})`, "ig"));
return strArr.map((ea, i) => {
if(ea.toLowerCase() === this.props.term.toLowerCase()){
return <mark key={`match${i}`} className="Search-suggestions-match">{ea}</mark>
} else {
return ea;
}
});
}
HTML inside of a string will NOT get added to the DOM, so you need to use JSX to return an actual React element instead.
Edit: added toLowerCase()
so that matches will ignore letter case like they do in the regular expression.
Upvotes: 3
Reputation: 6998
Typically you should not pass JSX as a string and expect React to render the element.
However there is an escape hatch that can be used to achieve what you want, check out dangerouslySetInnerHTML
From the docs:
dangerouslySetInnerHTML
is React's replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it's easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it's dangerous
So you could still do something like this:
render() {
...
return (
<ul className="Search-suggestions-component">
{
this.state.suggestions.map((value, i) => (
<li key={i} dangerouslySetInnerHTML={{ __html: value }} />
)
}
</ul>
)
}
Upvotes: 1