13

I have a React component defined in JSX which returns a cell using either td or th, e.g.:

if(myType === 'header') {
  return (
    <th {...myProps}>
      <div className="some-class">some content</div>
    </th>
  );
}

return (
  <td {...myProps}>
    <div className="some-class">some content</div>
  </td>
);

Would it be possible to write the JSX in such a way that the HTML tag is taken from a variable? Like:

let myTag = myType === "header" ? 'th' : 'td';
return (
  <{myTag} {...myProps}>
    <div className="some-class">some content</div>
  </{myTag}>
);

The above code returns an error:

"unexpected token" pointing at {.

I am using Webpack with the Babel plugin to compile JSX.

0stone0
  • 34,288
  • 4
  • 39
  • 64
Greg
  • 8,230
  • 5
  • 38
  • 53

3 Answers3

12

Try setting your component state and rendering like so:

render: function() {
    return(
        <this.state.tagName {...myProps}>
          <div className="some-class">some content</div>
        </this.state.tagName>
    );
},
0stone0
  • 34,288
  • 4
  • 39
  • 64
steveinatorx
  • 705
  • 9
  • 22
  • 4
    Eh, thanks for the tip. It will work without worrying about the state, just assign the tag name to a variable and use it inside JSX, e.g.: `let tx = 'td'; return (...` and so on. – Greg Sep 09 '16 at 07:19
  • 8
    Actually, the variable name must start with a capital letter, otherwise react treats it as a HTML tag and renders `tx` instead of the value of the variable. If the variable name is `Tx` then it correctly renders its content (i.e. `td` or `th`). – Greg Sep 09 '16 at 07:47
  • well but how to do that without "this..." statement after the "<"? – Малъ Скрылевъ Apr 05 '20 at 14:00
  • This can be used like OP intended: `const Wrapper = (condition) ? 'th' : 'td';` Then use it like a normal component: `` – 0stone0 Dec 28 '22 at 15:08
6

You can do something like:

const content = <div> some content </div>
return (
  {myType === 'header'
    ? <th>{content}</th>
    : <td>{content}</td>
  }
)

Note that this does not really solve your question about "dynamic tag" but rather the problem you seem to have.

Kev
  • 5,049
  • 5
  • 32
  • 53
  • Did you test this solution? Will it work without `dangerouslySetInnerHTML`? Will I not run into the problem described in http://stackoverflow.com/questions/36800148/how-to-render-jsx-html-that-is-inside-variable-or-prop and http://stackoverflow.com/questions/23616226/insert-html-with-react-variable-statements-jsx ? – Greg Sep 09 '16 at 07:10
  • It's not doing the same thing. In your link they use strings with html tags in them. It's not what I am doing here. – Kev Sep 09 '16 at 08:52
3

The first answer did not work for my case so I solved it in another way. From React documentation each element converts to pure JS like this.

So it is possible to create elements for React component that are dynamic like this:

let myTag = myType === "header" ? 'th' : 'td';

React.createElement(
  myTag,
  {className: 'some-class'},
  <div className="some-class">some content</div>
)
ThisIsWilliam
  • 995
  • 8
  • 10