React without JSX and why it's important


Quick setup
npm create vite@latest my-app -- --template react
cd my-app
npm install tailwindcss @tailwindcss/vite
// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
react(),
// Add this
tailwindcss()],
})
/* index.css */
@import "tailwindcss";
Create component without JSX
And yes, you can write React componentg without JSX, I will show you how and why you shouldn’t
We will use React.createElement to generate our element instead of using JSX
import React from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
const element = React.createElement(
// DOM element
'h1',
// Attributes
{className: 'text-3xl font-bold underline'},
// Children
'Hello, world!')
createRoot(document.getElementById('root')).render(element)
Sweet it’s working
But now what if I need nested element ? It’s also possible
import React from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
const element = React.createElement(
'section',
{className: 'border border-red-500 border-solid', id: 'main-heading'},
React.createElement(
'h1',
{className: 'text-3xl font-bold underline'},
'Hello, world!'
),
React.createElement(
'p',
null,
'I am Gilles, a software engineer!'
)
)
createRoot(document.getElementById('root')).render(element)
We are starting to see the main problem of React.createElement but let me exagerate it
import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
const element = React.createElement(
'div',
{
className: 'min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-4'
},
React.createElement(
'div',
{ className: 'max-w-2xl w-full bg-white rounded-2xl shadow-xl border border-slate-200 overflow-hidden' },
React.createElement(
'div',
{ className: 'bg-gradient-to-r from-blue-600 to-indigo-600 px-8 py-6' },
React.createElement(
'h1',
{
className: 'text-3xl font-bold text-white mb-2',
id: 'main-heading'
},
'Complex Nested Example'
),
React.createElement(
'p',
{ className: 'text-blue-100 text-lg' },
'This demonstrates more complex nesting with multiple elements and attributes.'
)
),
React.createElement(
'div',
{ className: 'p-8 space-y-6' },
React.createElement(
'div',
{ className: 'space-y-4' },
React.createElement('h2', { className: 'text-2xl font-semibold text-slate-800 border-b border-slate-200 pb-2' }, 'Subheading'),
React.createElement('p', { className: 'text-slate-600 leading-relaxed' }, 'Another paragraph nested deeper in the structure with improved readability and spacing.')
),
React.createElement(
'div',
{ className: 'bg-slate-50 rounded-lg p-6' },
React.createElement('ul', { className: 'space-y-3' },
React.createElement('li', { className: 'flex items-center text-slate-700' },
React.createElement('span', { className: 'w-2 h-2 bg-blue-500 rounded-full mr-3' }),
'Enhanced Item 1 with better styling'
),
React.createElement('li', { className: 'flex items-center text-slate-700' },
React.createElement('span', { className: 'w-2 h-2 bg-blue-500 rounded-full mr-3' }),
'Enhanced Item 2 with better styling'
),
React.createElement('li', { className: 'flex items-center text-slate-700' },
React.createElement('span', { className: 'w-2 h-2 bg-blue-500 rounded-full mr-3' }),
'Enhanced Item 3 with better styling'
)
)
),
React.createElement(
'div',
{ className: 'flex justify-center pt-4' },
React.createElement('button', {
className: 'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-8 py-3 rounded-full shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-blue-300'
}, 'Click me')
)
)
)
);
createRoot(document.getElementById('root')).render(element)
Nesting, nesting and… nesting, yes it does work but it’ll be horrible to maintain and to read, that’s why JSX is useful, JSX is immediately more readable, familiar to anyone who knows HTML, and significantly easier to maintain.
I will deep-dive into JSX in a future article but here is the code with JSX
import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
const App = () => {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-4">
<div className="max-w-2xl w-full bg-white rounded-2xl shadow-xl border border-slate-200 overflow-hidden">
<div className="bg-gradient-to-r from-blue-600 to-indigo-600 px-8 py-6">
<h1
className="text-3xl font-bold text-white mb-2"
id="main-heading"
>
Complex Nested Example
</h1>
<p className="text-blue-100 text-lg">
This demonstrates more complex nesting with multiple elements and attributes.
</p>
</div>
<div className="p-8 space-y-6">
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-slate-800 border-b border-slate-200 pb-2">
Subheading
</h2>
<p className="text-slate-600 leading-relaxed">
Another paragraph nested deeper in the structure with improved readability and spacing.
</p>
</div>
<div className="bg-slate-50 rounded-lg p-6">
<ul className="space-y-3">
<li className="flex items-center text-slate-700">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
Enhanced Item 1 with better styling
</li>
<li className="flex items-center text-slate-700">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
Enhanced Item 2 with better styling
</li>
<li className="flex items-center text-slate-700">
<span className="w-2 h-2 bg-blue-500 rounded-full mr-3"></span>
Enhanced Item 3 with better styling
</li>
</ul>
</div>
<div className="flex justify-center pt-4">
<button className="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-8 py-3 rounded-full shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-blue-300">
Click me
</button>
</div>
</div>
</div>
</div>
);
};
createRoot(document.getElementById('root')).render(<App />)
And imagine if you just create component for each of your needs it will be cleaner and cleaner
Subscribe to my newsletter
Read articles from Gilles Ferrand directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Gilles Ferrand
Gilles Ferrand
Full stack engineer but passionnated by front-end Angular Expert / NX / JavaScript / Node / Redux State management / Rxjs