Lets say I have an array of objects:
const options = [
{
text: "this is the text",
description: "The word 'test' should be bold"
},
{
text: "this is the text",
description: "The word 'another-word' should be bold"
}
]
the component renders something like this:
return (
{
options.map(option => {
<p className="text-green-500">{option.description}</p>
})
}
)
Now I have to make the word/s "test" and "another-word" bold respectively. In some cases it has to only be characters inside a word.
I answered it by replacing the value of description.
instead of:
description: "this is the text"
I changed it too:
description: <div>this is the <strong>text></strong></div>
You could create a function which replaces the string in '' with a <b> wrappers.
const highlight = (text) => text.replace(/'([^']+)'/g, "<b>$1</b>")
Then set the innerHTML like this:
return options.map(({ description }) =>
<p dangerouslySetInnerHTML={{ __html: highlight(description) }}></p>
)
You need to sanitize the string before doing this if these string are user inputs.
const highlight = (text) => text.replace(/'([^']+)'/g, "<b>$1</b>")
function App() {
const options = [{
text: "this is the text",
description: "The word 'test' should be bold"
},
{
text: "this is the text",
description: "The word 'another-word' should be bold"
}
]
return options.map(({ description }) =>
<p dangerouslySetInnerHTML={{ __html: highlight(description) }}></p>
)
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can avoid the innerHTML route entirely. In that case, you need split each string into fragments and then render them.
const highlight = (text) =>
Array.from(text.matchAll(/([^']*)'*([^']*)'*([^']*)/g), ([m, p1, p2, p3]) =>
m ? (
<>
{p1}
<b>{p2}</b>
{p3}
</>
) : null
);
And render it like this:
return options.map(({ description }) =>
<p>{highlight(description)}</p>
)
This is probably the easiest way to do it, just return a chunk of JSX from a function that deals with bolding the part of the text.
Stackblitz to run the code: https://stackblitz.com/edit/react-ts-gewz6v?file=App.tsx,index.tsx
const options = [
{
text: 'this is the text',
description: "The word 'test' should be bold",
},
{
text: 'this is the text',
description: "The word 'another-word' should be bold",
},
];
const boldText = (text) => {
const termToBold = text.match(/'([^']+)'/)[1];
const startIndex = text.toLowerCase().indexOf("'");
return (
<React.Fragment>
{text.slice(0, startIndex)}
<strong>
{text.slice(startIndex, startIndex + 2 + termToBold.length)}
</strong>
{text.slice(startIndex + 2 + termToBold.length)}
</React.Fragment>
);
};
return (
<div>
{' '}
{options.map((option) => {
return <p className="text-green-500">{boldText(option.description)}</p>;
})}
</div>
);
Related
This question already has an answer here:
Why doesn't my arrow function return a value?
(1 answer)
Closed 24 days ago.
I encounter the following question fairly often, but never really found a good duplicate target. Most of the time due to a lot of irrelevant overhead code. With this question I'm trying to craft a bare bones example that can be used as easily be used as duplicate target.
I've got an array of to-do items:
[
{ id: 1, task: "go to the grocery store", isDone: false },
{ id: 2, task: "walk the dog", isDone: true },
{ id: 3, task: "buy a present for John", isDone: false },
]
It doesn't matter where this array comes from.
It could be hard-coded:
const todos = [
{ id: 1, task: "go to the grocery store", isDone: false },
{ id: 2, task: "walk the dog", isDone: true },
{ id: 3, task: "buy a present for John", isDone: false },
];
It might come from a static file loaded on the server.
import todos from "../data/todos.json";
It might be the result of an web API call.
useEffect(() => {
fetch("https://api.example.com/v1.0/me/todo-items")
.then(response => response.json())
.then(todos => setTodos(todos))
}, []);
It might be build by the end-user as part of the application logic.
function handleAddTodoSubmit(e) {
e.preventDefault();
const todo = { id: nextID, task, isDone };
setTodos(todos => [...todos, todo]);
setNextID(nextID => nextID + 1);
setAddTodoDialogOpen(false);
}
No matter how todos is defined, the following does NOT render the to-do items:
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => {
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
})}
</ul>
);
}
When I inspect the resulting structure, I can see that the <ul> element is present, but it doesn't contain any <li> elements. See the snippet down below to run this yourself.
const TODOS = [
{ id: 1, task: "go to the grocery store", isDone: false },
{ id: 2, task: "walk the dog", isDone: true },
{ id: 3, task: "buy a present for John", isDone: false },
];
function ASCIICheckbox({ isChecked }) {
const check = isChecked ? "x" : " ";
return (
<React.Fragment>[{check}]</React.Fragment>
);
}
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => {
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
})}
</ul>
);
}
function App() {
return (
<div>
<h1>My todo list:</h1>
<TodoList todos={TODOS} />
</div>
);
}
ReactDOM.createRoot(document.querySelector("#root"))
.render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
I expect the 3 tasks to be rendered, but they are not.
How do I fix my render and display the items inside the collection?
The reason why the to-do items aren't rendered is because the map() callback doesn't have a return value.
Let's first look at the arrow function documentation of MDN:
Function body
Arrow functions can have either a concise body or the usual block
body.
In a concise body, only a single expression is specified, which
becomes the implicit return value. In a block body, you must use an
explicit return statement.
const func = (x) => x * x;
// concise body syntax, implied "return"
const func2 = (x, y) => {
return x + y;
};
// with block body, explicit "return" needed
…
(todo) => {
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
}
Uses a block body, but doesn't have a return statement, therefore the return value is undefined.
We can solve this in multiple ways, the first one being simply adding the return statement to the callback.
(todo) => {
return ( // <- notice the return
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
);
}
const TODOS = [
{ id: 1, task: "go to the grocery store", isDone: false },
{ id: 2, task: "walk the dog", isDone: true },
{ id: 3, task: "buy a present for John", isDone: false },
];
function ASCIICheckbox({ isChecked }) {
const check = isChecked ? "x" : " ";
return (
<React.Fragment>[{check}]</React.Fragment>
);
}
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => {
return ( // <- notice the return
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
);
})}
</ul>
);
}
function App() {
return (
<div>
<h1>My todo list:</h1>
<TodoList todos={TODOS} />
</div>
);
}
ReactDOM.createRoot(document.querySelector("#root"))
.render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
The second solution is changing the block body into a concise body. This can be done by removing the {/} block delimiters.
(todo) => ( // <- notice the change from `{` into `(`
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
)
const TODOS = [
{ id: 1, task: "go to the grocery store", isDone: false },
{ id: 2, task: "walk the dog", isDone: true },
{ id: 3, task: "buy a present for John", isDone: false },
];
function ASCIICheckbox({ isChecked }) {
const check = isChecked ? "x" : " ";
return (
<React.Fragment>[{check}]</React.Fragment>
);
}
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => ( // <- notice the change from `{` into `(`
<li key={todo.id}>
<pre>
<ASCIICheckbox isChecked={todo.isDone} />
{" "}
{todo.task}
</pre>
</li>
))}
</ul>
);
}
function App() {
return (
<div>
<h1>My todo list:</h1>
<TodoList todos={TODOS} />
</div>
);
}
ReactDOM.createRoot(document.querySelector("#root"))
.render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
If you're having trouble understanding what happens in the second solution, let me explain the grouping operator (/) first. In React (specifically JSX) it's common to see normal parentheses in combination with an arrow function. However the feature can be explained using basic JavaScript.
The main reason for using them is so you can split up your arrow function with concise body into a multiline statement.
const doubles = nrs.map((nr) => nr * 2);
// could also be written as (notice the additional parentheses)
const doubles = nrs.map((nr) => (nr * 2));
// which can be split across lines
const doubles = nrs.map((nr) => (
nr * 2 // <- now imagine this being a complex statement
));
Any expression can be placed in parentheses, it doesn't have to be in combination with an arrow function. const name = "John Doe" could be written as const name = ("John Doe") and yield the same result.
In the above example placing nr * 2 on a separate line is counter intuitive, because it's such a small expression. However the readability of JSX (which is one large expression) benefits a lot from being spread across multiple lines.
<ul>
{nrs.map((nr) => <li>complex and long structure {nr * 2}</li>)}
</ul>
// could also be written as (notice the additional parentheses)
<ul>
{nrs.map((nr) => (<li>complex and long structure {nr * 2}</li>))}
</ul>
// which can be split across lines
<ul>
{nrs.map((nr) => (
<li>
complex and long structure {nr * 2}
</li>
))}
</ul>
I am using antd components for my react app. I have a Text component wrapped inside of Popover component. Now in my case this Popover is applied to one particular column of table, i.e. every row-element in that column has a Popover component rendered for it upon mouse hovering.
title: "Name",
dataIndex: "name",
key: "name-key",
sortType: "string",
sortDirections: ["descend", "ascend"],
sorter: (a, b) => a.name.length - b.name.length,
render: (text, record) => (
<Popover>
<Text onMouseOver={handleOnMouseOverCommitId}> {name} </Text>
</Popover>
)
I want to get hold of the row-element's value, the one contained by the above Text component whenever I hover over it. In this case the value denoted by {name} above.
I tried getting it with e.target.value via onMouseOver event, but it returned undefined.
I think I get the reason behind it, because the event.target returns an html node of type <span>.
With a normal div element e.target.value has worked in the past for me. But doing the same thing with a predefined component like antd's Text seems a bit trickier.
Just to elaborate, the Popover has two buttons and based on which button user clicks, I need to render some other components, something like an overlay component.
But in order to do that I would also need to get hold of the text value which originally triggered the Popover.
Below is the code(most of the things removed for preciseness).
record.name is what I ultimately need to capture.
<Popover
content={
<>
<Space>
<Button onClick={showSomeOverlayPaneForName}>
{"View Details for record.name"}
</Button>
<Button href={"https://abc.xyz.com/" + record.role}>
{"View Role Details"}
</Button>
</Space>
</>
}
trigger={"hover"}
>
<Text style={{"color": blue.primary}} copyable={true} onMouseOver={handleOnMouseOverName}>{record.name}</Text>
</Popover>
The handleOnMouseOverName function(which doesn't work anyway) :
const handleOnMouseOverName = (e) => {
//console.log("e.target.value :--- ", e.target.value);
setCurrentActiveName(e.target.value)
}
And once my currentActiveName variable is set(via useState), I use that value inside my function showSomeOverlayPaneForName
const showSomeOverlayPaneForName = (e) => {
axios
.get(
`some-url`,
{
params: {name: currentActiveName}
}
)
.then((response) => {
setData(response.data);
}).catch(reason => {
//xyz
});
}
You need to pass on the record of the enclosing render function to the handleOnMouseOverName function.
Check the following example
import React from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Space, Table, Button, Popover } from 'antd';
const App = () => {
const data = [
{
key: '1',
name: 'John Brown',
address: 'New York No. 1 Lake Park',
role: 'admin',
},
{
key: '2',
name: 'Jim Green',
address: 'London No. 1 Lake Park',
role: 'user',
},
{
key: '3',
name: 'Joe Black',
address: 'Sidney No. 1 Lake Park',
role: 'manager',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (name, record) => {
const content = (
<>
<Space>
<Button
onClick={() => {
viewDetail(record);
}}
>
{'View Details for ' + record.name}
</Button>
<Button href={'https://abc.xyz.com/' + record.role}>
{'View Role Details'}
</Button>
</Space>
</>
);
return (
<>
<Popover content={content} title="Details">
<div
onMouseOver={() => {
handleOnMouseOverName(record);
}}
>
{name}
</div>
</Popover>
</>
);
},
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
const handleOnMouseOverName = (record) => {
console.log(record);
};
const viewDetail = (record) => {
console.log(record);
};
return <Table columns={columns} dataSource={data} />;
};
export default App;
Output:
I hope this helps.
From antd docs: https://ant.design/components/popover/#header
Apparently you're supposed to render the <Popover/> with a content={content}-prop
For example
const content = <div>Content to render under title</div>
const App = () => {
const value = "Text to hover";
return (
<Popover content={content} title="Title">
<Text>{value}</Text>
</Popover>
)
}
Update:
Basically i want the same output but i restructured the content. I'm not sure if your answers are still up for that.
Please check my sandbox feel free to fork it here:
https://codesandbox.io/s/get-the-property-value-forked-hutww
So on ContentData.js i want my image alt tag to be dynamic and pull the content of it from key name it something like this alt={this.name} and it will generate to alt="My alt tags"
See the codes below:
Content.js
import React, { Component } from "react";
import mainListsItems from "./ContentData";
class Content extends Component {
render() {
const myContent = mainListsItems.map((lists, k) => (
<>
<div key={k}>{lists.text}</div>
{lists.mainContent.map((subcontent, j) => {
return <div key={j}>{subcontent.contentAll}</div>;
})}
</>
));
return <>{myContent}</>;
}
}
export default Content;
ContentData.js
import React from "react";
const listsData = [
{
id: 1,
name: "My alt tags",
text: (
<>
<p>Lorem Imsum</p>
</>
),
mainContent: [
{
contentAll: (
<>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
</p>
<img
alt=""
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
/>
</>
)
}
]
}
];
export default listsData;
content is defined inside the object while the object is being defined. So there is no name yet when content is being defined. Only after the assignment does name exist. You're referencing something that doesn't exist yet. So instead you can create a function that will be called at a later point after the object is defined and then the name can be referenced as shown below.
export default function App() {
const myData = [
{
id: 1,
name: "Lorem Ipsum",
content: function(){
return (
<>
<img
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
alt={this.name}
/>
</>
)
}
}
];
const output = myData.map((x) => (
<>
<div key={x.id}>
<p>{x.name} sa</p>
<p>{x.content()}</p>
</div>
</>
));
return <div className="App">{output}</div>;
}
The this, in your case is referring the window object.
You can try to pass the name as a function value.
Something like this :
const myData = [
{
id: 1,
name: "Lorem Ipsum",
content: (alt) => (
<>
<img
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
alt={alt}
/>
</>
)
}
];
const output = myData.map((x) => (
<div key={x.id}>
<p>{x.name} sa</p>
<p>{x.content(x.name)}</p>
</div>
));
You can replace the object in your myData array with a self executing function like this:
const myData = [
function(){
const entry = {
id: 1,
name: "Lorem Ipsum",
}
return {
...entry,
content: (
<>
<img
src="your image source"
alt={entry.name}
/>
</>
)
}
}()
];
I am trying to map through an object that is passed as prop and want to display different HTML elements for different object values
Object;
const allDesc = {description: "Title Description", description1: "Intro
Description", description3:"Sub title", description3: "Sub Description"}
Code:
<div>
{Object.keys(allDesc).map((desc, index) => {
if (allDes[desc] !== "") {
return (
<>
<h1>allDesc.description</h1>
<p>allDesc.description1</p>
<h3>allDesc.description2</h3>
<p>allDesc.description3</p>
</>
);
}
})}
</div>
This approach displays nothing, what would be the correct approach for mapping through an object and displaying different HTML elements for different object values. Thanks!
map over the Object.entries. If the key matches "description" return the value as an <h1>, otherwise return the value as a <p>.
function Example({ allDesc }) {
return (
<div>
{Object.entries(allDesc).map(([key, value]) => {
if (key === 'description') return <h1>{value}</h1>;
if (key === 'description3') return <h3>{value}</h3>;
return <p>{value}</p>;
})}
</div>
);
};
const allDesc = {description: 'Title Description', description1: 'Intro Description', description3: 'Another Description', description4: 'More text' };
ReactDOM.render(
<Example allDesc={allDesc} />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Please try this.
<div>
{Object.keys(allDesc).map((desc, index) => {
if (allDes[desc] !== "") {
return (
<>
{
desc === 'description' ? <h1>allDes[desc]</h1> :
<p>allDes[desc]</p>
}
</>
);
}
})}
</div>
this allDes[desc] is have the value of all field you loop from the Object keys.
I have a custom autocomplete, so when you type, it will display a list of suggestions based on the input value. In the list, I would like to bold the characters that are the same as the input value.
So if I have a list of suggestions: "alligator", "lima", "lime", and I typed "li", then the suggestions would look like this:
alligator
lima
lime
I have this simple map in my jsx file:
<ul>
{matches.map(function(match, idx){
let re = new RegExp(value, 'g');
let str = match.replace(re, '<b>'+ value +'</b>');
return <li key={idx}>{str}</li>
})}
</ul>
where value is the input value. It displays the list but in this string format
al<b>li</b>gator
<b>li</b>ma
<b>li</b>me
Not sure how to go about with React. I thought of using dangerouslyinnerhtml or something like that, but I think that's a last resort thing. I would like to avoid that if possible.
This my autocomplete component:
class Autocomplete extends Component{
constructor(props){
super(props);
this.state = {
value: '',
matches: [],
showMatches: false
}
}
searchListing(){
api.call {
that.setState({
showMatches: true,
matches: a
});
})
}
}
handleOnChangeInput(e){
let value = e.target.value;
this.setState({ value: value})
if(value !== ''){
this.searchListing(e);
}else{
// console.log("value", e.target.value);
this.setState({
showMatches: false,
matches: []
})
}
}
render(){
let matches = this.state.matches;
let value = this.state.value;
let matchesHtml;
if(this.state.showMatches){
matchesHtml = <ul>
{matches.map(function(match, idx){
let re = new RegExp(value, 'g');
let str = match.replace(re, '<b>'+ value +'</b>');
return <li key={idx} dangerouslySetInnerHTML={{__html: str}}></li>
})}
</ul>
}
return(
<div>
<input placeholder="type a name" onChange={this.handleOnChangeInput}/>
{matchesHtml}
</div>
);
}
}
Writing your own highlighting code could lead down a rabbit hole. In my answer, I assume only simple text (no HTML within the strings, no charset edge cases) and valid non-escaped RegExp pattern string.
Instead of building a new string, you could build a new array, in which you could put JSX.
A React component can also return an array of elements:
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
The logic behind
As a simple proof of concept, here's the logic we could use:
const defaultHighlight = s => <em>{s}</em>;
// Needed if the target includes ambiguous characters that are valid regex operators.
const escapeRegex = v => v.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
/**
* Case insensitive highlight which keeps the source casing.
* #param {string} source text
* #param {string} target to highlight within the source text
* #param {Function} callback to define how to highlight the text
* #returns {Array}
*/
const highlightWord = (source, target, callback) => {
const res = [];
if (!source) return res;
if (!target) return source;
const regex = new RegExp(escapeRegex(target), 'gi');
let lastOffset = 0;
// Uses replace callback, but not its return value
source.replace(regex, (val, offset) => {
// Push both the last part of the string, and the new part with the highlight
res.push(
source.substr(lastOffset, offset - lastOffset),
// Replace the string with JSX or anything.
(callback || defaultHighlight)(val)
);
lastOffset = offset + val.length;
});
// Push the last non-highlighted string
res.push(source.substr(lastOffset));
return res;
};
/**
* React component that wraps our `highlightWord` util.
*/
const Highlight = ({ source, target, children }) =>
highlightWord(source, target, children);
const TEXT = 'This is a test.';
const Example = () => (
<div>
<div>Nothing: "<Highlight />"</div>
<div>No target: "<Highlight source={TEXT} />"</div>
<div>Default 'test': "<Highlight source={TEXT} target="test" />"</div>
<div>Multiple custom with 't':
"<Highlight source={TEXT} target="t">
{s => <span className="highlight">{s}</span>}
</Highlight>"
</div>
<div>Ambiguous target '.':
"<Highlight source={TEXT} target=".">
{s => <span className="highlight">{s}</span>}
</Highlight>"
</div>
</div>
);
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
.highlight {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
No need to use dangerouslySetInnerHTML here.
This highlightWord function can take any function to wrap the matched string.
highlight(match, value) // default to `s => <em>{s}</em>`
// or
highlight(match, value, s => <span className="highlight">{s}</span>);
I'm doing minimal regex string escaping based on another answer on Stack Overflow.
The Highlight component
As shown, we can create a component so it's "more react"!
/**
* React component that wraps our `highlightWord` util.
*/
const Highlight = ({ source, target, children }) =>
highlightWord(source, target, children);
Highlight.propTypes = {
source: PropTypes.string,
target: PropTypes.string,
children: PropTypes.func,
};
Highlight.defaultProps = {
source: null,
target: null,
children: null,
};
export default Highlight;
It uses a render prop, so you'd have to change your rendering to:
<ul>
{matches.map((match, idx) => (
<li key={idx}>
<Highlight source={match} target={value}>
{s => <strong>{s}</strong>}
</Highlight>
</li>
))}
</ul>
Just use dangerouslySetInnerHTML but take attention it make to inadvertently expose your users to a cross-site scripting (XSS) attack
...
const valueToBold = (match: string) => {
const regex = new RegExp(searchFilterValue, 'g');
return match.replace(regex, '<b>$&</b>');
};
return (
...
<ul>
{matches.map((match, idx)=> (
<li key={idx}>
<span dangerouslySetInnerHTML={{ __html:valueToBold(match) }} />
</li>
))}
</ul>
...
)
You just append your mapper as children inside your auto complete component.
<CustomAutocomplete>
<ul>
{
matches.map(function(match, idx){
let re = new RegExp(value, 'g');
let str = match.replace(re, '<b>'+ value +'</b>');
return (<li key={idx}>{str}</li>)
})
}
</ul>
</CustomAutocomplete>