Are you sure there is a #root element in your document? Is the javascript code located in the head or in the body?
The code you gave works fine already if you copy/paste it into your console on this page and target document.body within rootApp instead of document.getElementById("root"); so I suspect your problem happens because of something external to it.
Additionally
- If you use - constyou should use- letinstead of- var, since you're declaring- statein the top level scope, it will be accessible within any nested scopes (your function's body)
 
- If you don't care about (3) you can access the button by passing - thisto- myFunctionwithin the- onclickattribute, doing so eliminates the need to use- getElementByIdinside- myFunctionas it will be given as an argument
 
- It's better to create the button element yourself and use - addEventListenerto add interactivity instead of using- innerHTML
 
As a bonus, this could be improved by using a checkbox instead of a button: you wouldn't have to synchronize the checked state all the time.   You can always style the checkbox to look like something else using css
Reworked code
let state = false;
function myFunction({ target }) {
  state = !state;
  target.value = state ? 'ON' : 'OFF';
}
// Let's try to get the #root element
const rootId = 'root';
let rootApp = document.getElementById(rootId);
// If you don't have a #root element, we can create one
if (!rootApp) {
  rootApp = document.createElement('div');
  rootApp.id = rootId;
  document.body.appendChild(rootApp);
}
// Create the button element and setup its attributes
const element = document.createElement('input');
element.type = 'button';
element.id = 'button';
// Make sure `value` is in sync with `state`
element.value = state ? 'ON' : 'OFF';
// Listen to click event
element.addEventListener('click', myFunction);
// Append to #root
rootApp.appendChild(element);
Here is a working CodeSandbox forked from yours and updated with my js