Learn React Without JSX

Why React Without JSX

  1. React is typically used to create single page, complex-workflow apps, but it can be added to an existing page — or website — simply and with very little work.
  2. React without JSX is very lean relative to with it.
  3. All the same state management exists without JSX.
  4. Once used to using React without JSX, this may become the preferred method!

React without JSX is accomplished through the React.createElement method which replaces the JSX markup tags.

HTML Code

Download all of these code files: REACTWITHOUTJSX.zip.

This HTML code has a loading page to indicate to the user that the page is being downloaded. It uses Bootstrap v5.0.0-alpha1 to dress-up the React output.

<!DOCTYPE html>
<!-- CUSTOMERS.HTML -->
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<!-- LOAD BOOTSTRAP CSS FILE -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
	<title>React Without JSX</title>
	<style>
	body {
		background-color: white;
	}
	.pencil::after {
		content: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTZweCIgaGVpZ2h0PSIxNnB4IiB2aWV3Qm94PSIwIDAgMTYgMTYiIGZpbGw9IiNmZmYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQogIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTEyLjE0Ni4xNDZhLjUuNSAwIDAgMSAuNzA4IDBsMyAzYS41LjUgMCAwIDEgMCAuNzA4bC0xMCAxMGEuNS41IDAgMCAxLS4xNjguMTFsLTUgMmEuNS41IDAgMCAxLS42NS0uNjVsMi01YS41LjUgMCAwIDEgLjExLS4xNjhsMTAtMTB6TTExLjIwNyAyLjVMMTMuNSA0Ljc5MyAxNC43OTMgMy41IDEyLjUgMS4yMDcgMTEuMjA3IDIuNXptMS41ODYgM0wxMC41IDMuMjA3IDQgOS43MDdWMTBoLjVhLjUuNSAwIDAgMSAuNS41di41aC41YS41LjUgMCAwIDEgLjUuNXYuNWguMjkzbDYuNS02LjV6bS05Ljc2MSA1LjE3NWwtLjEwNi4xMDYtMS41MjggMy44MjEgMy44MjEtMS41MjguMTA2LS4xMDZBLjUuNSAwIDAgMSA1IDEyLjVWMTJoLS41YS41LjUgMCAwIDEtLjUtLjVWMTFoLS41YS41LjUgMCAwIDEtLjQ2OC0uMzI1eiIvPg0KPC9zdmc+);
	}
	.trash::after {
		content: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTZweCIgaGVpZ2h0PSIxNnB4IiB2aWV3Qm94PSIwIDAgMTYgMTYiIGZpbGw9IiNmZmYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQogIDxwYXRoIGQ9Ik01LjUgNS41QS41LjUgMCAwIDEgNiA2djZhLjUuNSAwIDAgMS0xIDBWNmEuNS41IDAgMCAxIC41LS41em0yLjUgMGEuNS41IDAgMCAxIC41LjV2NmEuNS41IDAgMCAxLTEgMFY2YS41LjUgMCAwIDEgLjUtLjV6bTMgLjVhLjUuNSAwIDAgMC0xIDB2NmEuNS41IDAgMCAwIDEgMFY2eiIvPg0KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNC41IDNhMSAxIDAgMCAxLTEgMUgxM3Y5YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0yVjRoLS41YTEgMSAwIDAgMS0xLTFWMmExIDEgMCAwIDEgMS0xSDZhMSAxIDAgMCAxIDEtMWgyYTEgMSAwIDAgMSAxIDFoMy41YTEgMSAwIDAgMSAxIDF2MXpNNC4xMTggNEw0IDQuMDU5VjEzYTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjQuMDU5TDExLjg4MiA0SDQuMTE4ek0yLjUgM1YyaDExdjFoLTExeiIvPg0KPC9zdmc+);
	}
	.loading {
		position: absolute;
		display: flex;
		align-items: center;
		top: 50%;
		left: 50%;
		transform: translate(-50%,-50%);
	}
	@keyframes loading {
		0% {
			height: 0;
		}
		50% {
			height: 50px;
		}
		100% {
			height: 0;
		}
	}
	.loading .l {
		background-color: dodgerblue;
		animation: loading .8s infinite;
		width: 10px;
		height: 0;
		margin: 0 3px;
		border-radius: 10px;
	}
	.loading .l:nth-child(2) {
		animation-delay: .1s;
	}
	.loading .l:nth-child(3) {
		animation-delay: .2s;
	}
	.loading .l:nth-child(4) {
		animation-delay: .3s;
	}
	.loading .l:nth-child(5) {
		animation-delay: .4s;
	}
	.loading .l:nth-child(6) {
		animation-delay: .5s;
	}
	.loading .l:nth-child(7) {
		animation-delay: .6s;
	}
	.loading .l:nth-child(8) {
		animation-delay: .7s;
	}
	</style>
</head>
<body>
	<div class="container text-center mt-5 mb-5">
		<h1>REACT Without JSX</h1>
	</div>

<noscript><p>You must enable JavaScript to use this site</p></noscript>

<div id="root">
	<div class="loading">
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
		<div class="l"></div>
	</div>
</div>

<!-- LOAD BOOTSTRAP AND REACT -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script>

<script src="ziptostate.js"></script>
<script src="customers.js"></script>

</body>
</html>

ZIP TO STATE JavaScript Code

This code is used by the app to find the customer's state based on the zip.

// ziptostate.js
function zipToState(zipcode)
{
	var zipbystate = [
		'--', '--', '--', '--', '--', 'NY', 'PR', 'PR', 'VI', 'PR', 'MA', 'MA', 'MA', 
		'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 'MA', 
		'MA', 'MA', 'RI', 'RI', 'NH', 'NH', 'NH', 'NH', 'NH', 'NH', 'NH', 'NH', 'NH', 
		'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'ME', 'VT', 'VT', 
		'VT', 'VT', 'VT', 'MA', 'VT', 'VT', 'VT', 'VT', 'CT', 'CT', 'CT', 'CT', 'CT', 
		'CT', 'CT', 'CT', 'CT', 'CT', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 
		'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'AE', 
		'AE', 'AE', 'AE', 'AE', 'AE', 'AE', 'AE', 'AE', '--', 'NY', 'NY', 'NY', 'NY', 
		'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 
		'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 
		'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 
		'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'NY', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 
		'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 
		'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 
		'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', 'PA', '--', 'PA', 'PA', 
		'PA', 'PA', 'DE', 'DE', 'DE', 'DC', 'VA', 'DC', 'DC', 'DC', 'DC', 'MD', 'MD', 
		'MD', 'MD', 'MD', 'MD', 'MD', '--', 'MD', 'MD', 'MD', 'MD', 'MD', 'MD', 'VA', 
		'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 
		'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 'VA', 
		'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 
		'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', 'WV', '--', 'NC', 'NC', 'NC', 
		'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 'NC', 
		'NC', 'NC', 'NC', 'NC', 'SC', 'SC', 'SC', 'SC', 'SC', 'SC', 'SC', 'SC', 'SC', 
		'SC', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 
		'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'GA', 'FL', 'FL', 'FL', 'FL', 'FL', 
		'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 'FL', 
		'FL', 'FL', 'AA', 'FL', 'FL', '--', 'FL', '--', 'FL', 'FL', '--', 'FL', 'AL', 
		'AL', 'AL', '--', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 
		'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 
		'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 'TN', 'MS', 'MS', 'MS', 'MS', 
		'MS', 'MS', 'MS', 'MS', 'MS', 'MS', 'MS', 'MS', 'GA', '--', 'KY', 'KY', 'KY', 
		'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 
		'KY', 'KY', 'KY', '--', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', 'KY', '--', 
		'--', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 
		'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 'OH', 
		'OH', 'OH', 'OH', 'OH', '--', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 
		'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'IN', 'MI', 
		'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 
		'MI', 'MI', 'MI', 'MI', 'MI', 'MI', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 
		'IA', 'IA', '--', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', '--', '--', '--', 
		'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', 'IA', '--', 'WI', 'WI', 'WI', 
		'--', 'WI', 'WI', '--', 'WI', 'WI', 'WI', 'WI', 'WI', 'WI', 'WI', 'WI', 'WI', 
		'WI', 'WI', 'WI', 'WI', 'MN', 'MN', '--', 'MN', 'MN', 'MN', 'MN', 'MN', 'MN', 
		'MN', 'MN', 'MN', 'MN', 'MN', 'MN', 'MN', 'MN', 'MN', '--', 'DC', 'SD', 'SD', 
		'SD', 'SD', 'SD', 'SD', 'SD', 'SD', '--', '--', 'ND', 'ND', 'ND', 'ND', 'ND', 
		'ND', 'ND', 'ND', 'ND', '--', 'MT', 'MT', 'MT', 'MT', 'MT', 'MT', 'MT', 'MT', 
		'MT', 'MT', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 
		'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'IL', '--', 'IL', 'IL', 
		'IL', 'IL', 'IL', 'IL', 'IL', 'IL', 'MO', 'MO', '--', 'MO', 'MO', 'MO', 'MO', 
		'MO', 'MO', 'MO', 'MO', 'MO', '--', '--', 'MO', 'MO', 'MO', 'MO', 'MO', '--', 
		'MO', 'MO', 'MO', 'MO', 'MO', 'MO', 'MO', 'MO', 'MO', '--', 'KS', 'KS', 'KS', 
		'--', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 'KS', 
		'KS', 'KS', 'KS', 'KS', 'NE', 'NE', '--', 'NE', 'NE', 'NE', 'NE', 'NE', 'NE', 
		'NE', 'NE', 'NE', 'NE', 'NE', '--', '--', '--', '--', '--', '--', 'LA', 'LA', 
		'--', 'LA', 'LA', 'LA', 'LA', 'LA', 'LA', '--', 'LA', 'LA', 'LA', 'LA', 'LA', 
		'--', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 'AR', 
		'AR', 'AR', 'OK', 'OK', '--', 'TX', 'OK', 'OK', 'OK', 'OK', 'OK', 'OK', 'OK', 
		'OK', '--', 'OK', 'OK', 'OK', 'OK', 'OK', 'OK', 'OK', 'TX', 'TX', 'TX', 'TX', 
		'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 
		'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 
		'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 
		'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'TX', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 
		'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', 'CO', '--', '--', 
		'--', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 'WY', 
		'ID', 'ID', 'ID', 'ID', 'ID', 'ID', 'ID', '--', 'UT', 'UT', '--', 'UT', 'UT', 
		'UT', 'UT', 'UT', '--', '--', 'AZ', 'AZ', 'AZ', 'AZ', '--', 'AZ', 'AZ', 'AZ', 
		'--', 'AZ', 'AZ', '--', '--', 'AZ', 'AZ', 'AZ', '--', '--', '--', '--', 'NM', 
		'NM', '--', 'NM', 'NM', 'NM', '--', 'NM', 'NM', 'NM', 'NM', 'NM', 'NM', 'NM', 
		'NM', 'NM', '--', '--', '--', '--', 'NV', 'NV', '--', 'NV', 'NV', 'NV', '--', 
		'NV', 'NV', '--', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', '--', 
		'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 
		'CA', 'CA', 'CA', 'CA', 'CA', 'CA', '--', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 
		'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 
		'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 'CA', 
		'AP', 'AP', 'AP', 'AP', 'AP', 'HI', 'HI', 'GU', 'OR', 'OR', 'OR', 'OR', 'OR', 
		'OR', 'OR', 'OR', 'OR', 'OR', 'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'WA', '--', 
		'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'AK', 'AK', 'AK', 'AK', 'AK'
	];

	var prefix = zipcode.substring(0, 3);
	var index = parseInt(prefix); /* converts prefix to integer */
	if(zipcode.length > 5 || isNaN(index) || index >= zipbystate.length)
		return "--";
	else
		return zipbystate[index];
}

React Without JSX Code

Download all of these code files: REACTWITHOUTJSX.zip.

Here is the React code that does not use even a smidgen of JSX. See this article for information about JavaScript classes.

Note: this code can be converted to earlier versions of EcmaScript using babeljs.io or es6console.com.

// customers.js
'use strict';

(function(){
	
	const ce = React.createElement; // to simplify code: React.createElement == ce

	function setClasses(classes) {
		classes = classes || {};
		if(typeof classes == "string") {
			classes = {className: classes};
		}
		else if(typeof classes != "object") {
			classes = {};
		}
		return classes;
	}

	// CHILDREN can be a string, an element object, or array of element objects
	function DIV(children, classes, options) {
		classes = setClasses(classes);
		return ce("div", Object.assign(classes, options), children);
	}
	function TH(children, options) {
		return ce("th", options, children);
	}
	function TD(children, options) {
		return ce("td", options, children);
	}
	function TR(children, options) {
		return ce("tr", options, children);
	}
	function THEAD(children) {
		return ce("thead", null, children);
	}
	function TBODY(children) {
		return ce("tbody", null, children);
	}
	function TABLE(children, classes, options) {
		classes = setClasses(classes);
		return ce("table", Object.assign(classes, options), children);
	}
	function A(children, href, classes, options) {
		classes = setClasses(classes);
		href = href || "";
		return ce("a", Object.assign(classes, {href:href}, options), children);
	}
	function BUTTON(children, classes, type, options) {
		classes = setClasses(classes);
		type = type || "";
		return ce("button", Object.assign(classes, {type:type}, options), children);
	}
	function FORM(children, options) {
		return ce("form", options, children);
	}
	function INPUT(type, name, classes, options) {
		classes = setClasses(classes);
		return ce("input", Object.assign({type:type,name:name}, classes, options), null);
	}
	function SPAN(children, classes, options) {
		classes = setClasses(classes);
		return ce("span", Object.assign(classes, options), children);
	}
	function I(classes) {
		return ce("i", setClasses(classes), null);
	}

	function CreateTable(obj) {
		const thead = THEAD([
			TR(TH("Customers", {colSpan:"4"})),
			TR([
				TH("NAME"),
				TH("ADDRESS"),
				TH("ZIP (STATE)", {colSpan:"2"})
			])
		]);
		const tbody = TBODY(obj.state.customers.map((cust) => {
			return TR([
				TD(cust.name),
				TD(cust.address),
				TD(cust.zip + " (" + zipToState(cust.zip) + ")"),
				TD([
					BUTTON(I("pencil"), "btn btn-sm btn-primary mr-1", null, {onClick:obj.editCust.bind(obj, cust.id)}),
					BUTTON(I("trash"), "btn btn-sm btn-danger", null, {onClick:obj.confirmDelete.bind(obj, cust.id)})
				], {className: "text-center"})
			]);
		}));
		return TABLE([thead,tbody], "table table-bordered table-striped table-hover");
	}

	function CreateAddForm(obj) {
		var div, divs = [];

		div = DIV([
			SPAN("Name", "input-group-text"),
			INPUT("text", "name", "form-control", {onChange:obj.formChange,autoComplete:"off",required:1})
		], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([
			SPAN("Address", "input-group-text"),
			INPUT("text", "address", "form-control", {onChange:obj.formChange,autoComplete:"off",required:1})
		], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([
			SPAN("Zipcode", "input-group-text"),
			INPUT("text", "zip", "form-control", {onChange:obj.formChange,autoComplete:"off",required:1}),
			BUTTON("Add","btn btn-success", "submit"),
			BUTTON("Cancel", "btn btn-secondary", null, {onClick:obj.cancel.bind(obj)})
		], "input-group input-group-md mb-2");
		divs.push(div);

		return FORM(divs, {onSubmit:obj.post.bind(obj)});
	}

	function CreateEditForm(obj) {
		var div, divs = [];

		div = DIV([
			SPAN("Name", "input-group-text"),
			INPUT("text", "name", "form-control", {defaultValue:obj.form.name,onChange:obj.formChange,autoComplete:"off",required:1})
		], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([
			SPAN("Address", "input-group-text"),
			INPUT("text", "address", "form-control", {defaultValue:obj.form.address,onChange:obj.formChange,autoComplete:"off",required:1})
		], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([
			SPAN("Zipcode", "input-group-text"),
			INPUT("text", "zip", "form-control", {defaultValue:obj.form.zip,onChange:obj.formChange,autoComplete:"off",required:1}),
			BUTTON("Save","btn btn-success", "submit"),
			BUTTON("Cancel", "btn btn-secondary", null, {onClick:obj.cancel.bind(obj)})
		], "input-group input-group-md mb-2");
		divs.push(div);

		return FORM(divs, {onSubmit:obj.put.bind(obj, obj.form.id)});
	}

	function CreateUnorderedList(obj) {
		return ce("ul", {key:"cust-list", className:"list-group"}, obj.state.customers.map((cust) => {
			return ce("li", {key:cust.id, className:"list-group-item"}, cust.name + " - " + cust.address + " - " + cust.zip);
		}));
	}

	window.onload = function () {
		setTimeout(() => {
			ReactDOM.render(ce(Customers), document.getElementById("root"));
		}, 1000);
	};

	class Customers extends React.Component {
		constructor(props) {
			super(props);
			this.form = {id:"",name:"",address:"",zip:""};
			this.state = {
				customers: [],
				mode: "table"
			};
			this.formChange = this.formChange.bind(this);
		}

		componentDidMount() {
			const t = this;
			fetch("http://www.prowaretech.com/api/customers", {
				method: "GET"
			}).then((res) => {
				return res.json();
			}).then((customers) => {
				t.setState((prevState) => {
					prevState.customers = customers;
					prevState.mode = "table";
					return prevState;
				});
			});
		}

		renderTable() {
			return DIV([
				CreateTable(this),
				DIV(BUTTON("New Customer", "btn btn-primary mb-3", null, {onClick:this.addCust.bind(this)}), "text-center"),
				CreateUnorderedList(this)
			], "container");
		}

		renderAddForm() {
			return DIV(CreateAddForm(this), "container");
		}

		renderEditForm() {
			return DIV(CreateEditForm(this), "container");
		}

		renderConfirmDelete() {
			return DIV([
				BUTTON("Confirm Delete", "btn btn-danger mr-1", null, {onClick:this.delete.bind(this)}),
				BUTTON("Cancel", "btn btn-secondary", null, {onClick:this.cancel.bind(this)})
			], "container text-center");
		}

		render() {
			switch(this.state.mode)
			{
				case "table":
					return this.renderTable();
				case "add":
					return this.renderAddForm();
				case "edit":
					return this.renderEditForm();
				case "confirm":
					return this.renderConfirmDelete();
			}
		}

		cancel() {
			this.setState((prevState) => {
				prevState.mode = "table";
				return prevState;
			});
		}

		editCust(custid) {
			this.state.customers.forEach((cust) => {
				if(cust.id == custid) {
					this.form.id = custid;
					this.form.name = cust.name;
					this.form.address = cust.address;
					this.form.zip = cust.zip;
					this.setState((prevState) => {
						prevState.mode = "edit";
						return prevState;
					});
				}
			});
		}

		confirmDelete(custid) {
			this.setState((prevState) => {
				this.form.id = custid;
				prevState.mode = "confirm";
				return prevState;
			});
		}

		addCust() {
			this.setState((prevState) => {
				prevState.mode = "add";
				return prevState;
			});
		}

		post(event) {
			event.preventDefault();
			const t = this;
			if(t.state.customers.length >= 10) {
				alert("10 records is the limit");
				return;
			}
			fetch("http://www.prowaretech.com/api/customers", {
				method: "POST",
				headers: {"Content-Type":"application/json"},
				body: JSON.stringify(t.form)
			}).then((res) => {
				return res.json();
			}).then((cust) => {
				t.setState((prevState) => {
					prevState.customers.push(cust);
					prevState.mode = "table";
					return prevState;
				});
			});
		}

		put(custid) {
			event.preventDefault();
			const t = this;
			fetch("http://www.prowaretech.com/api/customers/" + custid, {
				method: "PUT",
				headers: {"Content-Type":"application/json"},
				body: JSON.stringify(t.form)
			}).then((res) => {
				return res.json();
			}).then((customer) => {
				t.setState((prevState) => {
					prevState.customers = prevState.customers.map((cust) => {
						if(cust.id == customer.id) {
							return customer;
						}
						else {
							return cust;
						}
					});
					prevState.mode = "table";
					return prevState;
				});
			});
		}

		delete() {
			const t = this;
			fetch("http://www.prowaretech.com/api/customers/" + t.form.id, {
				method: "DELETE"
			}).then((res) => {
				return res.json();
			}).then((deleted) => {
				t.setState((prevState) => {
					prevState.customers = prevState.customers.filter((cust) => {
						return cust.id != deleted.id;
					});
					prevState.mode = "table";
					return prevState;
				});
			});
		}

		formChange(event) {
			const t = event.target;
			this.form[t.name] = t.value;
		}
	}

})();

Download all of these code files: REACTWITHOUTJSX.zip.

Internet Explorer Compatible Code

Here is the above code transformed into Internet Explorer compatible code using ES6CONSOLE.com

// customers.js
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

(function () {

	var ce = React.createElement; // to simplify code: React.createElement == ce

	function setClasses(classes) {
		classes = classes || {};
		if (typeof classes == "string") {
			classes = { className: classes };
		} else if ((typeof classes === "undefined" ? "undefined" : _typeof(classes)) != "object") {
			classes = {};
		}
		return classes;
	}

	// CHILDREN can be a string, an element object, or array of element objects
	function DIV(children, classes, options) {
		classes = setClasses(classes);
		return ce("div", Object.assign(classes, options), children);
	}
	function TH(children, options) {
		return ce("th", options, children);
	}
	function TD(children, options) {
		return ce("td", options, children);
	}
	function TR(children, options) {
		return ce("tr", options, children);
	}
	function THEAD(children) {
		return ce("thead", null, children);
	}
	function TBODY(children) {
		return ce("tbody", null, children);
	}
	function TABLE(children, classes, options) {
		classes = setClasses(classes);
		return ce("table", Object.assign(classes, options), children);
	}
	function A(children, href, classes, options) {
		classes = setClasses(classes);
		href = href || "";
		return ce("a", Object.assign(classes, { href: href }, options), children);
	}
	function BUTTON(children, classes, type, options) {
		classes = setClasses(classes);
		type = type || "";
		return ce("button", Object.assign(classes, { type: type }, options), children);
	}
	function FORM(children, options) {
		return ce("form", options, children);
	}
	function INPUT(type, name, classes, options) {
		classes = setClasses(classes);
		return ce("input", Object.assign({ type: type, name: name }, classes, options), null);
	}
	function SPAN(children, classes, options) {
		classes = setClasses(classes);
		return ce("span", Object.assign(classes, options), children);
	}
	function I(classes) {
		return ce("i", setClasses(classes), null);
	}

	function CreateTable(obj) {
		var thead = THEAD([TR(TH("Customers", { colSpan: "4" })), TR([TH("NAME"), TH("ADDRESS"), TH("ZIP (STATE)", { colSpan: "2" })])]);
		var tbody = TBODY(obj.state.customers.map(function (cust) {
			return TR([TD(cust.name), TD(cust.address), TD(cust.zip + " (" + zipToState(cust.zip) + ")"), TD([BUTTON(I("pencil"), "btn btn-sm btn-primary mr-1", null, { onClick: obj.editCust.bind(obj, cust.id) }), BUTTON(I("trash"), "btn btn-sm btn-danger", null, { onClick: obj.confirmDelete.bind(obj, cust.id) })], { className: "text-center" })]);
		}));
		return TABLE([thead, tbody], "table table-bordered table-striped table-hover");
	}

	function CreateAddForm(obj) {
		var div,
		    divs = [];

		div = DIV([SPAN("Name", "input-group-text"), INPUT("text", "name", "form-control", { onChange: obj.formChange, autoComplete: "off", required: 1 })], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([SPAN("Address", "input-group-text"), INPUT("text", "address", "form-control", { onChange: obj.formChange, autoComplete: "off", required: 1 })], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([SPAN("Zipcode", "input-group-text"), INPUT("text", "zip", "form-control", { onChange: obj.formChange, autoComplete: "off", required: 1 }), BUTTON("Add", "btn btn-success", "submit"), BUTTON("Cancel", "btn btn-secondary", null, { onClick: obj.cancel.bind(obj) })], "input-group input-group-md mb-2");
		divs.push(div);

		return FORM(divs, { onSubmit: obj.post.bind(obj) });
	}

	function CreateEditForm(obj) {
		var div,
		    divs = [];

		div = DIV([SPAN("Name", "input-group-text"), INPUT("text", "name", "form-control", { defaultValue: obj.form.name, onChange: obj.formChange, autoComplete: "off", required: 1 })], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([SPAN("Address", "input-group-text"), INPUT("text", "address", "form-control", { defaultValue: obj.form.address, onChange: obj.formChange, autoComplete: "off", required: 1 })], "input-group input-group-md mb-2");
		divs.push(div);

		div = DIV([SPAN("Zipcode", "input-group-text"), INPUT("text", "zip", "form-control", { defaultValue: obj.form.zip, onChange: obj.formChange, autoComplete: "off", required: 1 }), BUTTON("Save", "btn btn-success", "submit"), BUTTON("Cancel", "btn btn-secondary", null, { onClick: obj.cancel.bind(obj) })], "input-group input-group-md mb-2");
		divs.push(div);

		return FORM(divs, { onSubmit: obj.put.bind(obj, obj.form.id) });
	}

	function CreateUnorderedList(obj) {
		return ce("ul", { key: "cust-list", className: "list-group" }, obj.state.customers.map(function (cust) {
			return ce("li", { key: cust.id, className: "list-group-item" }, cust.name + " - " + cust.address + " - " + cust.zip);
		}));
	}

	window.onload = function () {
		setTimeout(function () {
			ReactDOM.render(ce(Customers), document.getElementById("root"));
		}, 1000);
	};

	var Customers = function (_React$Component) {
		_inherits(Customers, _React$Component);

		function Customers(props) {
			_classCallCheck(this, Customers);

			var _this = _possibleConstructorReturn(this, (Customers.__proto__ || Object.getPrototypeOf(Customers)).call(this, props));

			_this.form = { id: "", name: "", address: "", zip: "" };
			_this.state = {
				customers: [],
				mode: "table"
			};
			_this.formChange = _this.formChange.bind(_this);
			return _this;
		}

		_createClass(Customers, [{
			key: "componentDidMount",
			value: function componentDidMount() {
				var t = this;
				fetch("http://www.prowaretech.com/api/customers", {
					method: "GET"
				}).then(function (res) {
					return res.json();
				}).then(function (customers) {
					t.setState(function (prevState) {
						prevState.customers = customers;
						prevState.mode = "table";
						return prevState;
					});
				});
			}
		}, {
			key: "renderTable",
			value: function renderTable() {
				return DIV([CreateTable(this), DIV(BUTTON("New Customer", "btn btn-primary mb-3", null, { onClick: this.addCust.bind(this) }), "text-center"), CreateUnorderedList(this)], "container");
			}
		}, {
			key: "renderAddForm",
			value: function renderAddForm() {
				return DIV(CreateAddForm(this), "container");
			}
		}, {
			key: "renderEditForm",
			value: function renderEditForm() {
				return DIV(CreateEditForm(this), "container");
			}
		}, {
			key: "renderConfirmDelete",
			value: function renderConfirmDelete() {
				return DIV([BUTTON("Confirm Delete", "btn btn-danger mr-1", null, { onClick: this.delete.bind(this) }), BUTTON("Cancel", "btn btn-secondary", null, { onClick: this.cancel.bind(this) })], "container text-center");
			}
		}, {
			key: "render",
			value: function render() {
				switch (this.state.mode) {
					case "table":
						return this.renderTable();
					case "add":
						return this.renderAddForm();
					case "edit":
						return this.renderEditForm();
					case "confirm":
						return this.renderConfirmDelete();
				}
			}
		}, {
			key: "cancel",
			value: function cancel() {
				this.setState(function (prevState) {
					prevState.mode = "table";
					return prevState;
				});
			}
		}, {
			key: "editCust",
			value: function editCust(custid) {
				var _this2 = this;

				this.state.customers.forEach(function (cust) {
					if (cust.id == custid) {
						_this2.form.id = custid;
						_this2.form.name = cust.name;
						_this2.form.address = cust.address;
						_this2.form.zip = cust.zip;
						_this2.setState(function (prevState) {
							prevState.mode = "edit";
							return prevState;
						});
					}
				});
			}
		}, {
			key: "confirmDelete",
			value: function confirmDelete(custid) {
				var _this3 = this;

				this.setState(function (prevState) {
					_this3.form.id = custid;
					prevState.mode = "confirm";
					return prevState;
				});
			}
		}, {
			key: "addCust",
			value: function addCust() {
				this.setState(function (prevState) {
					prevState.mode = "add";
					return prevState;
				});
			}
		}, {
			key: "post",
			value: function post(event) {
				event.preventDefault();
				var t = this;
				if (t.state.customers.length >= 10) {
					alert("10 records is the limit");
					return;
				}
				fetch("http://www.prowaretech.com/api/customers", {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify(t.form)
				}).then(function (res) {
					return res.json();
				}).then(function (cust) {
					t.setState(function (prevState) {
						prevState.customers.push(cust);
						prevState.mode = "table";
						return prevState;
					});
				});
			}
		}, {
			key: "put",
			value: function put(custid) {
				event.preventDefault();
				var t = this;
				fetch("http://www.prowaretech.com/api/customers/" + custid, {
					method: "PUT",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify(t.form)
				}).then(function (res) {
					return res.json();
				}).then(function (customer) {
					t.setState(function (prevState) {
						prevState.customers = prevState.customers.map(function (cust) {
							if (cust.id == customer.id) {
								return customer;
							} else {
								return cust;
							}
						});
						prevState.mode = "table";
						return prevState;
					});
				});
			}
		}, {
			key: "delete",
			value: function _delete() {
				var t = this;
				fetch("http://www.prowaretech.com/api/customers/" + t.form.id, {
					method: "DELETE"
				}).then(function (res) {
					return res.json();
				}).then(function (deleted) {
					t.setState(function (prevState) {
						prevState.customers = prevState.customers.filter(function (cust) {
							return cust.id != deleted.id;
						});
						prevState.mode = "table";
						return prevState;
					});
				});
			}
		}, {
			key: "formChange",
			value: function formChange(event) {
				var t = event.target;
				this.form[t.name] = t.value;
			}
		}]);

		return Customers;
	}(React.Component);
})();