JSFiddle - React, Tailwind, and code Playground

HTML

<div id=sim class=no>Simulate?</div><!--div id=options><input name="scale" type="text" value="50,50" size="8"></div>-->
<canvas id=c width="500" height="500"></canvas>

CSS

html, body {
		margin: 0;
		background-color: hsla(0,0%,10%,1.00);
		overflow: hidden;
		color: white;
	} * {-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}
	#c {
		background-color: hsla(0,0%,0%,1.00); position: absolute;
		top: calc(50% - 500px/2);
		left: calc(50% - 500px/2);
	}
	#sim {
		position: absolute;
		top: calc(50% - 540px/2 - 6px);
		left: calc(50% - 500px/2);
		border: 1px solid;
		border-left-width: 10px;
		border-right-width: 10px;
		padding: 2px;
		cursor: pointer;
	}
	#sim.no {
		border-color: hsla(359,91%,52%,1.00);
	}
	#sim.yes {
		border-color: hsla(118,91%,52%,1.00);
	}
	#options {
		position: absolute;
		top: calc(50% - 540px/2 - 6px);
		left: calc(50% - 500px/2 + 82px);
	}

JavaScript

var ce = document.getElementById('c'),				// Canvas element
	c = ce.getContext('2d'),						// Context
	sim = document.getElementById('sim'),			// "Simulate?" button
	highlighted = [-1,-1],							// Mouse position
	clicking = false,								// Use for disabled and hidden click and drag functionality
	simulating = false,								// Is it happening?
	cells = [],										// The data
	size = [50, 50],								// Default size
	vsize = [ce.width/size[0], ce.height/size[1]],	// Pre-set size
	bg = null;										// Grid background placeholder

function draw() {
	
	//ce.width = ce.width;							// Basic clear
	
	if(!simulating) c.fillStyle = bg;				// Grid background
	else c.fillStyle = 'hsla(180,100%,25%,.15)';	// Fancy graphics
	c.fillRect(0,0,ce.width, ce.height);
	
	if(simulating) c.drawImage(ce, 1, -1, ce.width, ce.height);	// Fancy graphics
	
	tC = cells;										// Temporary cells (for checking against previous frame)
	for(var y = 0; y < size[1]; y++) {
		for(var x = 0; x < size[0]; x++) {
			var cell = tC[x][y], ne = 0;			// The relevant cell; alive cell count
			if(simulating) {						// If simulating, otherwise just save processing time/power
				// top topright right bottomright bottom bottomleft left topleft
				var   x2 = x+1,   x3 = x-1,   y2 = y+1,   y3 = y-1; // Math
				if(tC[x][y3] !== undefined && tC[x][y3]) ne++;			// T
				if(tC[x][y2] !== undefined && tC[x][y2]) ne++;			// TR
				if(tC[x2] !== undefined) {
					if(tC[x2][y]) ne++;									// R
					if(tC[x2][y3] !== undefined && tC[x2][y3]) ne++;	// BR
					if(tC[x2][y2] !== undefined && tC[x2][y2]) ne++;	// B
				}
				if(tC[x3] !== undefined) {
					if(tC[x3][y]) ne++;									// BL
					if(tC[x3][y3] !== undefined && tC[x3][y3]) ne++;	// L
					if(tC[x3][y2] !== undefined && tC[x3][y2]) ne++;	// TL
				}
				
				/*
					1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
					2. Any live cell with two or three live neighbours lives on to the next...