JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>

<html>

<body>
    <div id="lightsOut">
        <table id="display">
            <tbody>
            </tbody>
            <caption>
                Solve
            </caption>
        </table>
        <form id="options">
            <label>
                Width:
                <input name="width" type="number" value="3" min="3" max="9" required>
            </label>
            <label>
                Height:
                <input name="height" type="number" value="3" min="3" max="9" required>
            </label>
            <button>
                Reset
            </button>
            <label>
                Input:
                <select name="mode">
                    <option value="lights">Lights</option>
                    <option value="walls">Walls</option>
                    <option value="play">Play</option>
                </select>
            </label>
        </form>
    </div>
</body>

<head>
    <link rel="stylesheet" href="LO.css">
    <script src="LO.js"></script>
</head>

</html>

CSS

body {
    /* base size */
    --mult: 30px;
    /* margins */
    --margin: calc(var(--mult) * 0.1);
    --margin2: calc(var(--margin) * 0.5);
    /* space between elements */
    --gap: calc(var(--mult) * 0.3);
    /* input heights */
    --input: calc(var(--mult) * 1.5);
    --select: calc(var(--input) * 0.5);
    /* colors */
    --main-bg: rgb(245, 245, 245);
    --ui-bg-on: rgb(235, 235, 235);
    --ui-bg-off: rgb(195, 195, 195);
    /* default border */
    --border: var(--margin) solid rgb(155, 155, 155);
    --solution: var(--margin) solid rgb(255, 0, 0);
    /* font style */
    font-size: 30px;
    font-family: Arial, Helvetica, sans-serif;

    margin: 0;

    #lightsOut {
        width: fit-content;
        background: var(--main-bg);
        border: var(--border);
        display: flex;
        line-height: var(--input);

        #display {
            margin: var(--margin);
            border-collapse: collapse;

            tbody {
                tr {
                    z-index: 0;

                    td {
                        cursor: pointer;
                        position: relative;
                        box-sizing: border-box;
                        z-index: 0;
                        width: var(--input);
                        height: var(--input);
                        background: var(--ui-bg-on);
                        border: var(--border);

                        &.off {
                            background: var(--ui-bg-off);
                        }

                        &.solution::after {
                            width: var(--gap);
                            height: var(--gap);
                            content: "";
                            display: flex;
                            position: relative;
                            margin: auto;
                            border-radius: 100%;
                            background-color: black;
                        }

                        &.wall {
   ...

JavaScript

// inRange function: Alexander (via Stack Overflow)
// Lesson: Keith Schwarz (via keithschwarz.com)

// Walls do not work, otherwise perfect!

// Shorthand Key:
// p = puzzle
// t = toggle
// x = horizontal index / column number
// y = vertical index / row number
// w = temporary width
// h = temporary height
// i = index
// j = jindex
// next = next free row


//
// Variables
//

// initial matrices
var puzzle = [];
var toggle = [];
var solution = [];
// initial variables
var width = 0;
var height = 0;
var area = 0;
var inputMode = 0;
// elements
const table = document.querySelector("tbody");
const form = document.getElementById("options");
const submit = document.querySelector("caption");
const select = document.querySelector("select");

// 
// Matrix Functions
// 

// check if coords (x, y) are in bounds
function inBounds(x, y) {
    return 0 <= y && y < height && 0 <= x && x < width
}

//
// Create the puzzle and its corresponding arrays
//

// update width, height, and area
function update() {
    let formData = new FormData(form);
    for (const entry of formData.entries()) {
        if (entry[0] == "width") width = Math.round(entry[1]);
        if (entry[0] == "height") height = Math.round(entry[1]);
        if (entry[0] == "mode") inputMode = entry[1];
    }
    area = width * height;
}

// update dimensions, populate display
function populate() {
    select.value = "lights";
    update();

    // populate
    table.replaceChildren();
    puzzle = Array(area).fill(true);
    toggle = Array.from({ length: area }, () => Array(area).fill(false));
    for (let y = 0; y < height; y++) {
        table.insertRow();
        for (let x = 0; x < width; x++) {
            let i = x + y * width;

            // table, puzzle
            table.rows[y].insertCell().addEventListener("click", function () {
                update();
                let cells = table.querySelectorAll("td")
                this.classList.remove("solution");
                if (inputMode ==...