1

Trying to append my react elements into a third-party rendered component(DOM element) without touching the third-party package.

SomeComponent defines and renders the tools data internally, it doesn't provide an API to custom or extend the tools. So I want to directly extend the tools view via DOM manipulation.

third-party.tsx:

import * as React from 'react';

export const SomeComponent = () => {
  const tools = [
    { value: 1, action: () => console.log('a') },
    { value: 2, action: () => console.log('b') },
    { value: 3, action: () => console.log('c') },
  ];
  return (
    <div>
      <ul className="tools-wrapper">
        {tools.map((tool) => (
          <li onClick={tool.action} key={tool.value}>
            {tool.value}
          </li>
        ))}
      </ul>
    </div>
  );
};

App.tsx:

import * as React from 'react';
import './style.css';
import { SomeComponent } from './third-party';

export default function App() {
  const customTools = [
    { value: 100, action: () => console.log('hello') },
    { value: 100, action: () => console.log('world') },
  ];
  const customToolElements = (
    <React.Fragment>
      {customTools.map((tool) => (
        <li key={tool.value} onClick={tool.action}>
          {tool.value}
        </li>
      ))}
    </React.Fragment>
  );
  React.useEffect(() => {
    const toolsWrapper = document.querySelector('.tools-wrapper');
    // Append react elements into third-party rendered DOM element.
    // Of course, it throws an error, customToolElements is not a DOM native Node type.
    toolsWrapper.appendChild(customToolElements);
  }, []);
  return (
    <div>
      <SomeComponent />
    </div>
  );
}

Is this possible to extend the component of third-party via DOM manipulation directly rather than a data-driven API?

1 Answer 1

2

It is not recommended to directly extend a third-party component through DOM manipulation.

Instead of trying to append the custom tools directly to the DOM, pass the custom tools as a prop to the SomeComponent and use them to render additional elements.

import * as React from 'react';

export const SomeComponent = (props) => {
  const tools = [
    { value: 1, action: () => console.log('a') },
    { value: 2, action: () => console.log('b') },
    { value: 3, action: () => console.log('c') },
    ...props.customTools
  ];
  return (
    <div>
      <ul className="tools-wrapper">
        {tools.map((tool) => (
          <li onClick={tool.action} key={tool.value}>
            {tool.value}
          </li>
        ))}
      </ul>
    </div>
  );
};

In the App.tsx file, pass the customTools prop to the SomeComponent when it is rendered.

import * as React from 'react';
import './style.css';
import { SomeComponent } from './third-party';

export default function App() {
  const customTools = [
    { value: 100, action: () => console.log('hello') },
    { value: 100, action: () => console.log('world') },
  ];

  return (
    <div>
      <SomeComponent customTools={customTools} />
    </div>
  );
}

I have removed the useEffect hook and the customToolElements variable.

React.useEffect(() => {
    const toolsWrapper = document.querySelector('.tools-wrapper');
    // Append react elements into third-party rendered DOM element.
    // Of course, it throws an error, customToolElements is not a DOM native Node type.
    toolsWrapper.appendChild(customToolElements);
}, []);
Sign up to request clarification or add additional context in comments.

3 Comments

Note: the component of third-party doesn't use React.forwardRef to forward the ref to the target element (the tools-wrapper in my case).
Yes, it is not recommended to directly extend a third-party component through DOM manipulation because doing so could cause unexpected behavior and is not considered a best practice. Create a new component that encapsulates and extends the functionality of the third-party component or utilizing the data-driven API of the third-party component is preferred/better solution.
@LinDu the solution is updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.