You would have to split the text up and wrap dates in a <span>
with a className
.
In the example below, I created a component called <FormattedShortStory />
that takes a className
, pattern
, and text
. It handles splitting-up the text and wrapping each token.
Edit
The pattern
needs to be a string
or RegExp
:
Note: The curly braces are required, if the pattern
is a literal string.
// Valid
<FormattedShortStory
className="date"
pattern={"\\d{4}"}
text={shortStory} />
// Valid
<FormattedShortStory
className="date"
pattern={/\d{4}/g}
text={shortStory} />
// Invalid
<FormattedShortStory
className="date"
pattern="\\d{4}"
text={shortStory} />
const { useEffect, useState } = React;
/*
* Ensures that the provided pattern is either a string or RegExp
* @param {string|RegExp} pattern - a regular expression pattern
* @returns {RegExp} - converts string to a RegExp or returns the pattern
* @throws Error
*/
const guardRegex = (pattern) => {
if (pattern instanceof RegExp) return pattern;
if (typeof pattern === 'string') return new RegExp(pattern, 'g');
throw new Error('pattern is neither a RegExp or string');
}
/*
* Tokenizes a string by a delimiter.
* Inspired by:
* - https://stackoverflow.com/a/17414844/1762224
* - https://docs.oracle.com/javase/8/docs/api/java/util/StringTokenizer.html
* @param {string} str - a string to be parsed
* @param {string|RegExp} delim - the delimiters
* @param {boolean} [returnDelims=false] - whether to return the delimiters as tokens
* @returns {string[]} - list of tokens
*/
const stringTokenizer = (str, delim, returnDelims = false) => {
const regex = guardRegex(delim), result = [];
let token, index;
while (str !== '') {
regex.lastIndex = 0;
token = regex.exec(str);
if (token === null) { break; }
index = token.index;
if (token[0].length === 0) { index = 1; }
result.push(str.substr(0, index));
if (returnDelims) {
result.push(token[0]);
}
index = index + token[0].length;
str = str.slice(index);
}
result.push(str);
return result;
}
const FormattedShortStory = ({ className, pattern, text }) => (
<p>
{stringTokenizer(text, pattern, true).map((token, index) =>
guardRegex(pattern).exec(token)
? <span key={token + index} className={className}>{token}</span>
: token
)}
</p>
);
const getData = () => Promise.resolve([{
id: 1,
BlogTitle: 'My first encounter with web development in 2014',
shortStory: 'Back in late 2014 when I was 15 years old, I was passionate about...',
}]);
const App = () => {
const [data, setData] = useState([]);
useEffect(() => { getData().then(setData); }, []);
return (
<div>
<h1>Blogs</h1>
{data.map(({ id, BlogTitle, shortStory }) => (
<div key={id}>
<h2>{BlogTitle}</h2>
<FormattedShortStory
className="date"
pattern={"\\d{4}"}
text={shortStory}
/>
</div>
))}
</div>
);
};
ReactDOM
.createRoot(document.getElementById("root"))
.render(<App />);
.date { color: red; font-weight: bold; }
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>