<p>The lightbulb is <span id="lightbulb">lit (1)</span></p>

<div>
  <button hidden id="turn-on">turn on</button>
  <button id="turn-off">turn off</button>
  <button id="break">break</button>

  <button hidden id="reset" onclick="history.go(0)">
    Reset
  </button>
</div>
body {
  display: grid;
  place-content: center;
  height: 90vh;
  background: gold;
  color: black;
}

body[data-state='unlit'] {
  background: #040a0f;
  color: gray
}

body[data-state='broken'] {
  background: gray;
}

#turn-on {
  background: gold;
  color: black;
}

#break {
  background: gray;
}
View Compiled
import {
  assign,
  createMachine,
  interpret
} from "https://cdn.skypack.dev/[email protected]";

const lightbulb = document.getElementById("lightbulb");
const turnBulbOn = document.getElementById("turn-on");
const turnBulbOff = document.getElementById("turn-off");
const breakBulb = document.getElementById("break");
const reset = document.getElementById("reset");

const machine = createMachine({
  initial: "lit",
  context: { switchCount: 0 },
  states: {
    lit: {
      entry: "switched",
      on: {
        OFF: "unlit",
        BREAK: { target: "broken", cond: "goodLightBulb" },
      },
    },
    unlit: {
      entry: "switched",
      on: {
        ON: "lit",
        BREAK: { target: "broken", cond: "goodLightBulb" },
      },
    },
    broken: {},
  },
}).withConfig({
  actions: {
    switched: assign({ switchCount: (context) => context.switchCount + 1 }),
  },
  guards: {
    goodLightBulb: (context) => context.switchCount <= 3,
  },
})

const service = interpret(machine);
service.start();

service.subscribe((state) => {
  lightbulb.innerText = `${state.value} (${state.context.switchCount})`;
  document.body.dataset.state = state.value;

  turnBulbOn.hidden = !state.can("ON");
  turnBulbOff.hidden = !state.can("OFF");
  breakBulb.hidden = !state.can("BREAK");

  reset.hidden = !state.matches("broken");
});

turnBulbOn.addEventListener("click", () => {
  service.send("ON");
});

turnBulbOff.addEventListener("click", () => {
  service.send("OFF");
});

breakBulb.addEventListener("click", () => {
  service.send("BREAK");
});
Run Pen

External CSS

  1. https://cdn.jsdelivr.net/npm/[email protected]/out/dark.css

External JavaScript

This Pen doesn't use any external JavaScript resources.