React: Inserting a line break in localised text - reactjs

I'm getting localised text from a JSON file and displaying it to the page, my problem is that the \n and <br> notations are being ignored.
I've made a code sandbox here to show how the text doesn't get put on more than one line.
import * as React from "react";
import { render } from "react-dom";
const App: React.FC = props => {
const Translations: {
[key: string]: {
fname: string;
};
} = {
en: {
fname: "I want to insert a break in this line of text so it shows on two lines \n doesnt work and <br> does either",
},
cn: {
fname: "我想在这一行文本中插入一个中断,以便在两行中显示\ n不起作用,而<br>可以",
}
};
const txt = Translations["en"];
return (
<div className="App">
<p>{txt.fname}</p>
</div>
);
};
const rootElement = document.getElementById("root");
render(<App />, rootElement);

In order to respect \n, you can add a style of white-space: pre-line or white-space: pre-wrap.
In React, it would look like this:
return (
<div className="App">
<p style={{ whiteSpace: "pre-line" }}>{txt.fname}</p>
</div>
);
Here is a forked sandbox.

use css property white-space: pre-line
<p style={{ whiteSpace: "pre-line" }}>{txt.fname}</p>

You could use dangerouslySetInnerHTML, however make sure to sanitize your input with smth like DOMPurify:
return (
<div className="App">
<p
dangerouslySetInnerHTML={{
__html: txt.fname
}}
/>
</div>
);
As mentioned in the comment, another way is to replace <br> with \n and add whiteSpace: "pre-line" css rule:
return (
<div className="App">
<p style={{ whiteSpace: "pre-line" }}>
{txt.fname.replace("<br>", "\n")}
</p>
</div>
);
Working sandbox.

You could always use JSX instead - it would look like this
en: {
fname: <p>"I want to insert a break in this line of text so it shows on two lines \n doesnt work and <br> does either"</p>
}
return (
<div className="App">
{txt.fname}
</div>
);

Related

How can I make new line string of Props used in react?

I'm having trouble with new line breaks in strings.
parent
<SampleComponent title="One \n Two \n Three">
children
type SampleComponentProps = {
title: string;
};
export const SampleComponent: FC<SampleComponentProps> = ({
title,
}) => {
return (
<div style={whiteSpace:'pre-line'}>{title}</div>
);
};
display
One \n Two \n Three
I would expect
One
Two
Three
The following code should work
return ({title.split("\\n").map((line, index) => (
<React.Fragment key={index}>
{line}
<br />
</React.Fragment>
))})
You can solve this problem by setting HTML directly from React, just using html and css, no using JS regex, or convert string to array then output.
<div
style={{whiteSpace: 'pre'}}
dangerouslySetInnerHTML={{ __html: ' One \n Two \n Three' }}
></div>
this is the result
Reference link: dangerously set innerHTML

how to add dynamic content inside a textarea tag using map method

i am currently working on chat application with sockets , when i get different messages i use an array and then use map method to display them in simple html tags like p etc it worked perfect but inside text-area its not working i also tried to set text-area value property with map method but only i see is [object object] . also how can i automatically move the scroll bar down when messages there are more messages.
here is the code
import { Fragment, useEffect } from "react";
import { format } from "date-fns";
const Chat = ({ name, message }) => {
const date = new Date();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
console.log("so bteay", message);
return (
<Fragment>
<div>
<h3 className="d-inline-block me-3"> Chat log </h3>
{name && (
<span className="me-3 d-inline-block">
<div
class="spinner-grow spinner-grow-sm text-success"
style={{ fontSize: "10px" }}
role="status"
>
<span class="visually-hidden">Loading...</span>
</div>
</span>
)}
<small className="text-muted d-block "> {name}</small>
<textarea
cols="70"
rows="8"
value={message.map((eachMsg) => {
return (
<Fragment>
{
<small className="text-muted d-inline-block">{`${hour}:${minute}:${second}`}</small>
}
<p
className="d-block shadow p-1 fw-bold rounded text-success"
style={{ fontFamily: "cursive" }}
>
{eachMsg}
</p>
</Fragment>
);
})}
></textarea>
</div>
</Fragment>
);
};
export default Chat;
You can only pass 1 child ( text in this case ) to text area. But you are trying to pass an array. If what you meant to do is to have as many as textareas as your array, this is how you should go about it:
const texts = ["Hi", "Bye","done"];
<div>
{texts.map((text) => (
<textarea>text</textarea>
))}
</div>
but if you are trying to have 1 textarea with all your texts inside it, first you need to create a long string using join method, and then render that string.
I think that you can't set html code inside textarea, unless you want to show it as a text?

React not able to render an array(state) in a single row

The state
state = {
posts: [],
}
The posts gets an API value of
{
"authors": [
{
"authorName": "Sideney Sheldon",
"authorImageURL": "http..."
},
{
"authorName": "Sideney Sheldon",
"authorImageURL": "http..."
},
....
]
}
code
render(){
const postList = posts.length ? (
posts.map(post => {
return (
<div className="" key={this.state.key}>
<div className="containerimager">
<img style={imgb} src={post.authorImageURL} />
</div>
<h6 style={{ marginTop:"23px"}} >{post.authorName}</h6>
</div>
)
})
) :
(
<div className="center">No posts to show</div>
);
return(
{postList}
)
}
The {postlist} returns objects but it returns each object in a new row in the webpage
I want all the results(images) in the same row
can anyone please help?
If you want multiple elements in the same row, you could achieve that with css. Use display: flex(by default flex-direction is row which is what you need) on the wrapper to postList. You can either pass it as a style though JSX or add a class that specifies this property
render(){
const postList = posts.length ? (
posts.map(post => {
return (
<div className="" key={this.state.key}>
<div className="containerimager">
<img style={imgb} src={post.authorImageURL} />
</div>
<h6 style={{ marginTop:"23px"}} >{post.authorName}</h6>
</div>
)
})
) : (
<div className="center">No posts to show</div>
);
return(
<div style={{display: 'flex'}}>{postList}</div>
)
}
Here's a CodeSandbox sample I created using your code.
If you're trying to line up the users horizontally (from left to right), CSS is the way to go. In particular, the <div> that is being mapped has, by default, the display: block style which makes it occupy its own row in the page.
To line up divs side by side, you need to somehow apply the display: inline-block style. In my example I used a style prop, but you will likely want to do it in CSS directly.
This is a CSS problem, you should use display: flex together with flex-direction: row on the parent div which will provide the desired result.
posts.map(post,index => {
return (
<div className="" key={this.state.key}>
<div className="containerimager">
<img style={imgb} src={post.authors[index].authorImageURL} />
</div>
<h6 style={{ marginTop:"23px"}} >{post.authors[index].authorName}</h6>
</div>
)
})
) : (
<div className="center">No posts to show</div>
);
Try this

'Unknown props' error when using react-tab-panel

I'm receiving an error when trying to implement the react-tab-panel in my application. I've followed the installation instructions to no avail.
This is the code which is producing the error:
import React from 'react';
import TabPanel from 'react-tab-panel'
const tabStyle = (props) => {
const baseStyle = {
padding: 10
}
return Object.assign(
baseStyle,
props.active?
{ color: 'red' }:
{ background: 'gray' }
)
}
const ExperimentDetail = ({ tabStyle }) => (
<div className="experiment-detail">
<TabPanel
tabAlign="center"
tabStyle={tabStyle}
>
<div tabTitle="first tab"> first </div>
<div tabTitle="second tab"> second </div>
<div tabTitle="third tab"> third </div>
</TabPanel>
</div>
);
export default ExperimentDetail;
The output is showing up as so, which is close to correct but with slight errors.
Thanks in advance for the help!
Reason is, you are using active props in TabStyle, but you are not passing in from ExperimentDetail component. One more thing you need to change, you need to use TabStyle name instead of tabStyle, because each react component must start with a uppercase.
And the main point is TabStyle is a react component, it will not return an object, it will return a html part so you can't use it with styling.
Use it in this way:
If you want to make a generic function that will return the style object, then write it in this way, create a separate file abc.js, put that function in that file, like this:
export function tabStyle(active){
const baseStyle = {
padding: 10
}
return Object.assign(
baseStyle,
props.active?
{ color: 'red' }:
{ background: 'gray' }
)
}
Import this function in your component:
import {tabStyle} from './abc /*path to this file*/';
Then use it in this way:
const ExperimentDetail = () => (
<div className="experiment-detail">
<TabPanel
tabAlign="center"
tabStyle={tabStyle(true)}
>
<div tabTitle="first tab"> first </div>
<div tabTitle="second tab"> second </div>
<div tabTitle="third tab"> third </div>
</TabPanel>
</div>
);
export default ExperimentDetail;
Check the working jsfiddle example: https://jsfiddle.net/ghoLrkjj/

How to render a multi-line text string in React

Suppose I have a text string that contains line-breaks, and I render it like this:
render() {
var text = "One\nTwo\nThree";
return <div>{text}</div>;
}
In HTML the line-breaks don't render as line-breaks. How should I do this in React? I don't want to convert to <br> tags and use dangerouslySetInnerHTML. Is there another way?
Make a new CSS-class
.display-linebreak {
white-space: pre-line;
}
Display your text with that CSS-class
render() {
const text = 'One \n Two \n Three';
return (
<div className="display-linebreak">
{text}
</div>
);
}
Renders with line-breaks (Sequences of whitespace will collapse into a single whitespace. Text will wrap when necessary). Like this:
One
Two
Three
You may also consider pre-wrap. More info here (CSS white-space Property).
You could try putting divs for each line
render() {
return (<div>
<div>{"One"}</div>
<div>{"Two"}</div>
<div>{"Three"}</div>
</div>);
}
Or
render() {
var text = "One\nTwo\nThree";
return (
<div>
{text.split("\n").map((i,key) => {
return <div key={key}>{i}</div>;
})}
</div>);
}
You could use CSS property "white-space: pre". I think this is the easiest way to handle this.
Try this one,
render() {
var text = "One\nTwo\nThree";
return <div style={{whiteSpace: 'pre-line'}}>{text}</div>;
}
Here the cleanest solution (afaik):
render(){
return <pre>
Line 1{"\n"}
Line 2{"\n"}
Line 3{"\n"}
</pre>
}
Instead of you can also use <div style={{whiteSpace:"pre"}}>, or any other html block element (like span or p with this style attribute)
You can use -webkit-user-modify: read-write-plaintext-only; in your div. It will format and understand things like \n and \p for instance.
You can make use of textarea tag of html, later you can add the styling to the textarea tag.
It pretty much solves your all issues including line breaks and tab spaces.
Cheerzz...
eg:
Your render will look something like below
render() {
var text = "One\nTwo\nThree";
return <textarea>{text}</textarea>;
}
Output:
One
Two
Three
You can safely run String.raw instead for this type of value.
const text = String.raw`One
Two
Three
`
render() {
return <div style={{ whiteSpace: "pre" }}>{text}</div>
}
You can also just use a <pre> tag which effectively does the same thing, but its less semantically clear if you're already using that for other purposes in your app.
<div style={{ whiteSpace: "break-spaces" }}> {JSON.stringify(state, null, " ")} </div>
We can use package name dedent to render multiline text:
const multilineText = `
This is line 1
This is line 2
This is line 3
`;
export default function App() {
return (
<>
<div style={{ whiteSpace: "pre-wrap" }}>{dedent(multilineText)}</div>
</>
);
}
We preferred having <br/>s instead and are using this simple function component in our TypeScript project:
import React, { FunctionComponent } from "react"
export const Multiline: FunctionComponent<{ text: string }> = ({ text }) => (
<>
{text.split(/\n|\r\n/).map((segment, index) => (
<>
{index > 0 && <br />}
{segment}
</>
))}
</>
)
Render your delimited text "My line one\nMy second line\nWhatevs..." inside a normal html textarea. I know it works because i just used it today ! Make the textarea readOnly if you must, and style accordingly.
this example in react.js component,
it will insert each line into a new div element by using (map , split) and it is a good example for comments/posts to support ltr/rtl style component at the same time and here is a simple example :
<div>
{ ' this is first line \n this is second line \n this is third line '.split('\n').map( line =>
<div key={ Math.random() * 10} dir="auto" style={{ textAlign: 'start'}}> {line} </div>
)}
</div>
also if your string data comming from API / react state you can use your string variable name as the follwing :
<div>
{ post_comments.split('\n').map( line =>
<div key={ Math.random() * 10} dir="auto" style={{textAlign: 'start'}}> {line} </div>
)}
</div>
this is just example , and change it based on your case/requirements.
and if you like you can replace div tag with p tag as per your request .
i hope this helpful for you

Resources