Injecting Dynamic Elements to Components
Tags: javascript, react, frontend
Published: 2018-05-19 03:28:37

---
title: Injecting Dynamic Elements to Components
description: Injecting React Components
published: true
tags: ["Javascript", "React", "Frontend"]
canonical_url: https://www.dylanpaulus.com/react/2017/07/26/injecting-react-tag-types/
---

Originally Posted: [dylanpaulus.com](https://www.dylanpaulus.com/react/2017/07/26/injecting-react-tag-types/)

# React: Injecting Dynamic Elements to Components

### Introduction

Let’s say we’re working on an UI component library using React JS. We make a super awesome looking button, maybe even the best button in the world. But suddenly, our computer shuts off without saving our component! Like Tenacious D, we create a tribute to the button which looks like:

```jsx
class AwesomeButton extends Component {
    render() {
        const { children, ...other } = this.props;

        return (
           <button {...other}>{children}</button> 
        );
    }
}
```

Everything is working great. We create buttons all over the place `<AwesomeButton onClick={doStuff}>Click ME</AwesomeButton>`.

The next day, the boss comes over, “This button is amazing, let’s make a button link to Google!” Easy enough, we create a new component that instead uses an anchor tag.

```jsx
class AwesomeButtonLink extends Component {
    render() {
        const { children, ...other } = this.props;

        return (
           <a {...other}>{children}</a> 
        );
    }
}
```

Weeks later, another programmer walks over, “Hey, we’re converting to using React Router. Can we get a button that can use the Link component?” Mumbling under your breath, we create yet another Awesome component.

```jsx
class AwesomeButtonReactRouterLink extends Component {
    render() {
        const { children, ...other } = this.props;

        return (
           <Link {...other}>{children}</Link> 
        );
    }
}
```

We have ourselves a problem. Everytime there is a new request we have to create new components that are very similar, just using slightly different render elements. What if the company decides to rebrand. Instead of blue, we are a red company now. Little changes to the visuals of these AwesomeButton components need to be updated individually. Think DRY! Is there a better way of doing this? Stay tuned.

### Dynamically Injecting Elements

What if the consumer of a component could define its base element? Let’s look at the example below:

```jsx
class AwesomeButton extends React.Component {
    render() {
        const { children, tag = "button", ...other } = this.props;
        const Tag = tag;

        return (
           <Tag {...other}>{children}</Tag> 
        );
    }
}
```

So we have this new property called tag. Tag will be our way of passing in an element/component into AwesomeButton. If the es6 destructing looks different, let me explain. We will pull out the `tag` prop from `this.props`. If no value is defined for tag, we will set its default value to be `"button"` (A Button HTML element). The next line, `const Tag = tag;` is so we can fulfill what React’s JSX considers a component. All components must be uppercased, where html elements need to be lowercase. Since we are using then variable `tag`, JSX will always treat the incoming values as a component. So, we have to uppercase our variable. We now render the prop `Tag` as our element. Whatever `tag` equals, that will be our element!

A few examples:

```jsx
<AwesomeButton onClick={doSomething}>Click Me!<AwesomeButton>
```

Will render the default button. `<button onClick={doSomething}>Click Me!</button>`

```jsx
<AwesomeButton tag="a" href={`/myPage`}>Click Me!<AwesomeButton>
```

Will render using an anchor tag `<a href={'/myPage'}>Click Me!</a>`

```jsx
<AwesomeButton tag={Link} to={`/myPage`}>Click Me!<AwesomeButton>
```

Will render using a React Router Link component `<Link to={'/myPage'}>Click Me!</Link>`

Neat! But why is this happening?

### JSX Transformations

Our JSX, in the render function, gets transformed into plain JavaScript functions that the browsers can use. With this in mind, our AwesomeButton’s JSX gets transformed into a `React.createElement()` function with the element name as the first argument. With the help of our good friend Babel, let’s see what different components compile to!

First, let’s look at a simple component that just renders a div with the text “test”.

```jsx
class AwesomeButton extends React.Component {
    render() {
        return (
           <div>test</div> 
        );
    }
}
```

[Compiled Example - Click Me!](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code_lz=MYGwhgzhAECCDuBTCB7AtogQgVwC65QDtpEAPXRQgExgCVExhcA6AYXQAcjLdoBvALAAoaKOgAnSlUTiAFAEp-wsSomJc2ccVnLVqgDxUAlgDcAfBQi59AemPnouvfIDcT6AF9hHoA)

If we look in the render method, we can see what our JSX actually compiles to.

![div Compiled Code](data:image/png;base64,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 "div Compiled Code")

Well that’s cool. So our div element just gets defined as the first parameter of `React.createElement`. I wonder what happens if we try this with our element injecting AwesomeButton?

```jsx
class AwesomeButton extends React.Component {
    render() {
        const { children, tag = "button", ...other } = this.props;
        const Tag = tag;

        return (
           <Tag {...other}>{children}</Tag> 
        );
    }
}
```

[\<AwesomeButton\>Click Me!\</AwesomeButton\>](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code_lz=MYGwhgzhAECCDuBTCB7AtogQgVwC65QDtpEAPXRQgExgCVExhcA6AYXQAcjLdoBvALAAoaKOgAnSlUTiAFAEp-wsSujAiEXnzUALAJYgqkwgBpouMAHNoAXmgAiAEZ4Che2eaeUuHTOgBfW3N9CGYOcRQOCABuZVVRdUJNaAAVKyCLS1ihOPjJXGxxYllc-NEAHjTrPk9mb19xfwA-PmB9Q2N_coB6KqboUpV5bJV_YX8gA)

Woah, our Tag variable just gets put where the element is! This is exactly the same to how components are treated in JSX. They get ploped straight into the first argument of `React.createElement`. Now, when the boss asks for a new feature in `AwesomeButton`, we only have to change this one implementation of the component. All consumers of the component might use it vastly differently, but we are able to keep our code DRY and highly reusable!