Native rendering and state

Reflect state with DOM attributes

Represent task state with native properties and meaningful attributes so CSS, JavaScript, and tests see one result.

For a small interface, the DOM can hold the state that directly controls presentation. A task card can expose completion through an attribute, a button through disabled, a disclosure through open, and a dialog through its native state.

Use properties for live control state and attributes for states that CSS or inspection should observe. toggleAttribute() is ideal for a present-or-absent flag. Update the button label in the same function so the action remains truthful after each change.

function setTaskComplete(card, complete) {
  card.toggleAttribute("data-complete", complete)
  const button = card.querySelector("[data-action=complete]")
  button.textContent = complete ? "Mark active" : "Complete"
  button.setAttribute("aria-pressed", String(complete))
}

setTaskComplete(card, !card.hasAttribute("data-complete"))

Only use aria-pressed when the button really behaves as a toggle. The visible label may change or stay stable, but the pressed state must match the action. ARIA reports a contract; it does not implement the state for you.

Do not keep three independent copies such as task.complete, data-complete, and .is-complete unless you have a clear synchronization boundary. One canonical record plus one render function is safer when state also persists or arrives from a server.

Native Boolean attributes are based on presence. hidden="false" is still present and therefore hidden. Remove the attribute or set the property to false. This is why toggleAttribute(name, boolean) reads more accurately than assigning a string.

Toggle a task repeatedly and assert the card attribute, button text, and aria-pressed value after every click in DevTools. Reload and note that DOM-only state is not persistence. Call the function directly with both true and false so the result does not depend on a previous click. If CSS shows completion while the button announces false, route every update through one setTaskComplete() function.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →