I'm looking to append a button after the 2nd paragraph in a react html markdown implementation. I am currently using react-markdown to compile my html code. A few things I am trying to do here:
Should I use ref to achieve this or is it as simple as appending with plain JavaScript?? Open to other suggestions if there is a better solution.
index.jsx
import React, { useEffect } = 'react'
import ReactMarkdown from 'react-markdown'
const Markdown = (props) => {
// props.contentHTML seems to be typeof string (with no html tags.
//ex: 'hello world' vs '<p>hello world</p>') but converts to appropriate element tags
const reactHTML = <ReactMarkdown children={props.contentHTML} />
useEffect(() => {
// how do i get 2nd element of that reactHTML p tag??
let secondPElement = ?? reactHTML.querySelector..... ??
// create element for my button
let button = document.createElement('button');
button.id = 'btn-1';
// error here: appendChild does not exist on type 'Element'
reactHTML.appendChild(button)
})
return (
{reactHTML}
)
}
export default Markdown
Unfortunately, I don't think there's a way to achieve this without doing something a little unorthodox (read: hacky).
TLDR: Here's a sandbox with what I think is a viable solution for you.
Continuing on, there are a couple of problems preventing your code from working.
When you define reactHTML
you're not actually defining HTML but rather a react Element
Object (because that's what JSX compiles it into).
This means that you won't be able to use DOM selectors on it (e.g. querySelector
and appendChild
) and that is why you get the error appendChild does not exist on type 'Element'
. This makes sense because the react Element
object does not have such a method.
The "solution" then, is to render your markdown content as you normally would, and only after being rendered go in and access the elements that you want. This can be easily achieved with the useEffect
hook very similar to what you're already doing:
const Markdown = (props) => {
const markdown = `
This is rendered as a '<p>' element
So is this one!
Me too!
`;
useEffect(() => {
// Get all of the <p> elements
const pElements = document.getElementsByTagName("p");
// Create a button
const button = document.createElement("button");
button.id = "btn-1";
button.innerHTML = "I'm a button!";
const refChild = pElements[1];
// Insert the button before the next sibling of the second <p> tag
refChild && refChild.parentNode.insertBefore(button, refChild.nextSibling);
}, []);
return <ReactMarkdown children={markdown} />;
};