CSS attribute selectors react when the matching DOM attribute changes. Set a real attribute such as data-state, and make the selector match the exact value stored in the markup.
Last updated: October 14, 2026.
<style>
.status-button[data-state="ready"] { background: #1769aa; color: white; }
.status-button[data-state="busy"] { opacity: 0.55; }
</style>
<button class="status-button" data-state="ready">Run</button>
<script>
const button = document.querySelector('.status-button');
button.addEventListener('click', () => {
button.dataset.state = 'busy';
});
</script>The dataset.state property writes the data-state attribute, so the browser recalculates selector matching automatically. Inspect the element in developer tools to confirm the final attribute name and value.
Distinguish attributes from JavaScript properties
MDN documents that setAttribute() updates an existing attribute or creates it. Custom JavaScript properties such as element.state = "busy" do not create a matching HTML attribute. Use dataset for data-* state or setAttribute() when the attribute name is dynamic.
For boolean attributes such as disabled, presence means true regardless of the string value. Remove the attribute or set the corresponding DOM property to false to turn it off.
Match the serialized value exactly
MDN’s attribute-selector reference describes exact, word, prefix, suffix, and substring matching. Values of custom data-* attributes are normally case-sensitive, so [data-state="Ready"] does not match ready.
Prefer a small vocabulary such as ready, busy, and error. Keep accessibility state synchronized when it has meaning: a disabled control should use the actual disabled property, while expanded widgets should update aria-expanded.
If the attribute changes correctly but the appearance does not, inspect the Computed Styles panel. A more specific selector, a later rule, an inline style, or an !important declaration may win the cascade. Selector matching can be correct even when another declaration supplies the final value.
Continue with shared CSS stylesheets, accessible tabs, and tracing JavaScript errors.