I've found a lot of questions that are similar to this but none that actually answer my question.
I have an object key called "text" that contains a string value. In the middle of the string I need a button element to render but I am getting [Object, Object] instead. I have tried other ways but they will only print the button as a string and not as an element.
In short, I have a string but need a word in the middle of the string to become a button.. How would you go about it?
import { Container, Button } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { InstructionsCard } from "components/layout/directory";
import {
RiNumber1 as OneIcon,
RiNumber2 as TwoIcon,
RiNumber3 as ThreeIcon,
} from "react-icons/ri";
const instructions = [
{
id: 1,
icon: OneIcon,
title: "step one",
text: "Parent/guardian must make the reservation for the minor through our website (Anyone under the age of 18).",
},
// attempting to render button[enter image description here][1]
{
id: 2,
icon: TwoIcon,
title: "step two",
text: `Parent/guardian will have to sign the minors waiver that is sent via email ${(
<Button>Email</Button>
)} after the reservation is made.`,
},
{
id: 3,
icon: ThreeIcon,
title: "step three",
text: "Parent/guardian must show proof of idenity at checkout or can submit a photo of their ID to our email. ",
},
];
function MinorSection() {
const classes = useStyles();
return (
<section className={classes.root}>
<Container className={classes.container}>
{instructions.map((_instruction, index) => {
return <InstructionsCard key={index} item={_instruction} />;
})}
</Container>
</section>
);
}
// custom styles
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(5, 0, 5, 0),
},
container: {
display: "flex",
flexDirection: "row",
justifyContent: "space-evenly",
},
}));
export default MinorSection;
Output: 1
EDIT: The InstructionsCard component is rendering the text like so
import { makeStyles } from "@mui/styles";
import { Card, CardContent, Typography, Divider } from "@mui/material";
const InstructionsCard = ({ item }) => {
const classes = useStyles();
const NumberIcon = item.icon;
return (
<Card className={classes.root}>
<CardContent>
<NumberIcon className={classes.icon} />
<Typography variant="h5" component="h6">
{item.title.toUpperCase()}
</Typography>
<Divider className={classes.divider} />
<Typography
variant="subtitle1"
component="p"
sx={{ mb: 1.5 }}
color="text.secondary"
>
{item.text}
</Typography>
</CardContent>
</Card>
);
};
const useStyles = makeStyles((theme) => ({
root: {
background: theme.palette.primary.main,
borderRadius: theme.spacing(5),
padding: theme.spacing(2),
margin: theme.spacing(5),
width: "100%",
textAlign: "center",
boxShadow: `0px 0px 10px 10px ${theme.palette.offset.main}`,
},
icon: {
background: theme.palette.secondary.dark,
width: "50px",
height: "50px",
padding: "15px",
borderRadius: theme.spacing(5),
},
divider: {
background: theme.palette.secondary.dark,
padding: "2px",
width: "15%",
margin: theme.spacing(1, "auto", 1, "auto"),
},
}));
export default InstructionsCard;
You can't put JSX elements within a template literal. Doing so will just attempt to stringify them, resulting in the infamous "[object Object]" (see Object.prototype.toString()).
Simply change your text
property to something React / JSX can render, like an array
text: [
"Parent/guardian will have to sign the minors waiver that is sent via email ",
<Button>Email</Button>,
" after the reservation is made."
]
or a fragment
text: (
<>
Parent/guardian will have to sign the minors waiver that is sent via email
<Button>Email</Button>
after the reservation is made.
</>
),
If you want to replace specific words in an otherwise static string literal, I would suggest something like the following...
const word = "email";
const text = "some text with the word email in it";
const nodes = text
.split(new RegExp(`(\\b${word}\\b)`, "i"))
.map((node, i) => (i % 2 ? <Button>{node}</Button> : node));
where nodes
is an array you can render directly in JSX.