If I have JSX like
<div>Hello there are 123 oranges</div>
Here's how text is set.
const Component = ({text}) => {
return(
<div>{text}</div>
)
}
I wanna make 123 red color. However, the text inside div is dynamic, so I can't insert span by hardcoding. Hopefully CSS can detect numeric but I couldn't find one by googling.
Are there any good and concise solutions?
It 's possible with dangerouslySetInnerHTML, you need regex to match the numeric part from your dynamic string and then generate the updated string with a style wrapped around that numeric part.
const yourText = yourText.replace(/\d+/, m => `<span style="color: red">${m}</span>` );
then pass this to dangerouslySetInnerHTML.
<div dangerouslySetInnerHTML={{__html: yourText}}></div>
You can perhaps try with regex
text.replaceAll(/(\d+)/g,'<span className="num">$1</span>')
String.prototype.replaceAll is an ES10 method.
Related
I am trying to build some HTML in the following format:
<h1>Title</h1>
<p>
Always existing sentence. Optional sentence.<br/>
Always existing sentence. Optional sentence.
</p>
<p>
<span>Always existing span</span>
<span>Optional span</span>
</p>
What is the best way to construct/render this?
The nearest I have got is some JSX:
const title = <h1>Title</h1>
const line1 = [`Always existing sentence.`];
const line2 = [`Always existing sentence.`];
if (condition) {
line1.push(`Optional sentence.`);
line2.push(`Optional sentence.`);
}
const para1 = React.createElement('p', null, [line1.join(' '), line2.join(' ')].join('<br/>'));
const spans = [React.createElement('span', null, `Always existing span`)];
if (condition2) {
spans.push(React.createElement('span', null, `Optional span`));
}
const para2 = React.createElement('p', null, spans.join('<br/>'));
return <>{title}{para1}{para2}</>;
This works apart from the final paragraph which renders as <p>[object Object]<br/>[object Object]</p>. I assume because the spans are ReactElements. But I don't know how to join() them. Or even if this is the best approach.
So, what is the best way to gradually build up HTML to render in React?
I believe what you're looking for is conditional rendering of JSX. You have the right idea with your pseudocode, you just need to change that if (condition) into checking for the value of a state variable. It's unclear if you're using the class syntax or hooks, so I'll provide an example using hooks for simplicity. The same idea applies regardless of which syntax you use.
Whenever state changes in React, the component will be re-rendered. With showOptionalContent set to false by default, the optional content will not be displayed. When showOptionalContent is changed to true, the component will re-render and the optional content will be displayed. You can use lifecycle methods or the useEffect hook to call a method that changes the state depending on when/why you want the optional content to be rendered.
const [showOptionalContent, setShowOptionalContent] = setState(false);
return (
<div>
<h1>Title</h1>
<div>Always rendered content</div>
{showOptionalContent && ( // only renders when showOptionalContent === true
<div>Optionally rendered content</div>
)}
<span>Always rendered content</span>
{showOptionalContent && ( // only renders when showOptionalContent === true
<span>Optionally rendered span</span>
)}
</div>
)
I ended up doing the following in order to achieve what I set out to:
const title = <h1>Title</h1>
const line1 = [`Always existing sentence.`];
const line2 = [`Always existing sentence.`];
if (condition) {
line1.push(`Optional sentence.`);
line2.push(`Optional sentence.`);
}
const para1 = <p>{line1.join(' ')}<br/>{line2.join(' ')}</p>;
//This is a huge span
const span1 = <span>Always existing span.</span>;
let span2 = null;
if (condition2) {
//This is a huge span
span2 = <span>Optional span.</span>;
}
const para2 = <p>{span1}{span2 && (<><br/>{span2}</>)}</p>;
return <>{title}{para1}{para2}</>;
Still seems a bit unclean, but it works and it was the best I could come up with.
In React, I want to be able to use style words within a string which is defined in a variable using template literals.
For that I am making use of a to just style that word.
I am getting HTMLIntrinsic usage error.
Note- Solutions given in SO to questions related to this does not solve the issue I have. Pls check the code.
How to circumvent this problem
Tried using dangerouslyinsertHTML, but not a recommended solution.
//Actual code
const temperature = "22";
const list = {
item: `The temperature is ${temperature}`
}
//To style it-
const temperature = "22";
const list = {
item: `The temperature is <span style={{color:'red'}}>${temperature}</span>`
}
//And the above list.item is inserted inside JSX like -
return (
<div>{list.item}</div>
)
The temperature(22) needs to be styled.
Instead of the template string, you can use JSX elements for generating HTML as usual, placed next to your text elements. Example:
item: (
<>
The temperature is
<span style={{color:'red'}}>
{temperature}
</span>
</>
)
I'm using a Fragment to wrap the text and elements together, but you can use something else like a div if you wish to style the wrapper too.
You can't use React in template-literal like that because the React component is an object. Using it with template-literal will result in this[object Object] . So I recommend use other way, for example the solution by #richardo
You can make this as simple as this, IF you are OK to not have object like you defined
return(
<div>The temperature is <span style={{color: 'red'}}>{temperature}</span></div>
)
It took me more than 2 hours to deeply understand the experience.
In the following snippet, return doesn't work as expected:
return
<VideoItem
key={video.etag}
changeVideo={changeVideo}
video={video} />;
For more clarification I wanted to have return and what should be returned in multiple lines.
But the line below neither works:
return
<VideoItem key={video.etag} changeVideo={changeVideo} video={video} />;
My mistake was that I had to do one of the following:
Write return and the rest in one single line:
return <VideoItem key={video.etag} changeVideo={changeVideo} video={video} />;
Wrap the returning result with parentheses:
return (
<VideoItem
key={video.etag}
changeVideo={changeVideo}
video={video} />);
Yes, the modern JS is THAT sensitive!
All your content should be wrapped inside a parent tag.
A typical return syntax looks like so:
return (
<div>
Everything you do should be here.......
</div>
);
Notice the parent <div></div>. You can change it to anything like <h1></h1>, <b></b>, etc.
I have following construct:
<h1>
<span>
</span>
</h1>
....
and
<div id="tourname">Riding trip arround the volcano</div>
Now the div with the id is filled by a php function and I would like that
my h1 looks like this:
<h1>
<span>Riding</span>
trip arround the volcano
</h1>
I managed to fill the h1 using this function:
$("h1").html($("#tourname").html());
but I have no idea how to split my string into 2 parts and fill one part
into that span and the rest behind the /span
Can you give a hint ?
Many thanks
You can do that in 2 ways .
1 - When you are writing using php , you can create the span for first word.
2 - Using jQuery. You can see the below code using jQuery
$(document).ready(function(){
var text = $("#tourname").html();
var firstword = text.substr(0,text.indexOf(' ')); // to get the first word
var remaining = text.substr(text.indexOf(' ')+1); // remianing words
var final = '<span>'+firstword+'</span> '+ remaining // combining by adding <span> around the first word
$("h1").html(final);
});
use this:
var strArr = $("#tourname").html().split(' ');
$("h1 span").html(strArr.shift());
$("h1").append(document.createTextNode(strArr.join(" ")));
This should be of some help.
Also consider this fiddle
This will be specific to your use only.
For more flexibility with number of text elements use strArr.splice(index, number_of_elements_to_include_in_span);
instead of strArr.shift();
I'm assuming it's not possible, but just in case it is or someone has a nice trick up their sleeves, is there a way to target certain characters using CSS?
For example make all letters z in paragraphs red, or in my particular case set vertical-align:sup on all 7 in elements marked with the class chord.
Hi I know you said in CSS but as everybody told you, you can't, this is a javascript solution, just my 2 cents.
best...
JSFiddle
css
span.highlight{
background:#F60;
padding:5px;
display:inline-block;
color:#FFF;
}
p{
font-family:Verdana;
}
html
<p>
Let's go Zapata let's do it for the revolution, Zapatistas!!!
</p>
javascript
jQuery.fn.highlight = function (str, className) {
var regex = new RegExp(str, "gi");
return this.each(function () {
this.innerHTML = this.innerHTML.replace(regex, function(matched) {return "<span class=\"" + className + "\">" + matched + "</span>";});
});
};
$("p").highlight("Z","highlight");
Result
That's not possible in CSS. Your only option would be first-letter and that's not going to cut it. Either use JavaScript or (as you stated in your comments), your server-side language.
The only way to do it in CSS is to wrap them in a span and give the span a class. Then target all spans with that class.
As far as I understand it only works with regular characters/letters. For example: what if we want to highlight all asterisk (\u002A) symbols on page. Tried
$("p").highlight("u\(u002A)","highlight");in js and inserted * in html but it did not worked.
In reply to #ncubica but too long for a comment, here's a version that doesn't use regular expressions and doesn't alter any DOM nodes other than Text nodes. Pardon my CoffeeScript.
# DOM Element.nodeType:
NodeType =
ELEMENT: 1
ATTRIBUTE: 2
TEXT: 3
COMMENT: 8
# Tags all instances of text `target` with <span class=$class>$target</span>
#
jQuery.fn.tag = (target, css_class)->
#contents().each (index)->
jthis = $ #
switch #.nodeType
when NodeType.ELEMENT
jthis.tag target, css_class
when NodeType.TEXT
text = jthis.text()
altered = text.replaceAll target, "<span class=\"#{css_class}\">$&</span>"
if altered isnt text
jthis.replaceWith altered
($ document).ready ->
($ 'div#page').tag '⚀', 'die'