HTML Guides for hidden
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The autocomplete attribute tells the browser whether it can assist the user in filling out a form field, and if so, what type of data is expected. The generic values "on" and "off" control whether the browser should offer autofill suggestions to the user. Since type="hidden" inputs are never displayed and never receive direct user input, these values don’t apply — there’s no user interaction to assist with.
According to the HTML specification, hidden inputs can have an autocomplete attribute, but only with specific named autofill detail tokens (like "transaction-id" or "cc-number"). These tokens serve a programmatic purpose by providing hints about the semantic meaning of the hidden value, which can be useful for form processing. The generic "on" and "off" values, however, are explicitly disallowed because they only relate to the user-facing autofill behavior.
This validation error matters for standards compliance and can indicate a logical mistake in your markup. If you added autocomplete="off" to a hidden input hoping to prevent the browser from caching or modifying the value, it won’t have that effect. Hidden input values are controlled entirely by the server or by JavaScript, not by browser autofill.
How to fix it
- Remove the autocomplete attribute if it’s not needed — this is the most common fix.
- Use a specific autofill token if you need to convey semantic meaning about the hidden value (e.g., autocomplete="transaction-id").
- Reconsider the input type — if the field genuinely needs autofill behavior controlled, it probably shouldn’t be type="hidden".
Examples
Incorrect: using autocomplete="off" on a hidden input
<form action="/submit" method="post">
<input type="hidden" name="token" value="abc123" autocomplete="off">
<button type="submit">Submit</button>
</form>
Incorrect: using autocomplete="on" on a hidden input
<form action="/submit" method="post">
<input type="hidden" name="session-id" value="xyz789" autocomplete="on">
<button type="submit">Submit</button>
</form>
Correct: removing the autocomplete attribute
<form action="/submit" method="post">
<input type="hidden" name="token" value="abc123">
<button type="submit">Submit</button>
</form>
Correct: using a specific autofill token
If the hidden input carries a value with a well-defined autofill semantic, you can use a named token:
<form action="/checkout" method="post">
<input type="hidden" name="txn" value="TXN-001" autocomplete="transaction-id">
<button type="submit">Complete Purchase</button>
</form>
This is valid because "transaction-id" is a specific autofill detail token recognized by the specification, unlike the generic "on" or "off" values.
Hidden inputs are designed to carry data between the client and server without any user interaction or visual presence. The browser does not render them, screen readers do not announce them, and they are entirely excluded from the accessibility tree. Because aria-* attributes exist solely to convey information to assistive technologies, adding them to an element that assistive technologies cannot perceive is contradictory and meaningless.
The HTML specification explicitly prohibits aria-* attributes on input elements with type="hidden". This restriction exists because WAI-ARIA attributes — such as aria-label, aria-invalid, aria-describedby, aria-required, and all others in the aria-* family — are meant to enhance the accessible representation of interactive or visible elements. A hidden input has no such representation, so these attributes have nowhere to apply.
This issue commonly arises when:
- JavaScript frameworks or templating engines apply aria-* attributes indiscriminately to all form inputs, regardless of type.
- A developer changes an input’s type from "text" to "hidden" but forgets to remove the accessibility attributes that were relevant for the visible version.
- Form libraries or validation plugins automatically inject attributes like aria-invalid onto every input in a form.
To fix the issue, simply remove all aria-* attributes from any input element that has type="hidden". If the aria-* attribute was meaningful on a previously visible input, no replacement is needed — the hidden input doesn’t participate in the user experience at all.
Examples
Incorrect: hidden input with aria-invalid
<form action="/submit" method="post">
<input type="hidden" name="referer" value="https://example.com" aria-invalid="false">
<button type="submit">Submit</button>
</form>
Correct: hidden input without aria-* attributes
<form action="/submit" method="post">
<input type="hidden" name="referer" value="https://example.com">
<button type="submit">Submit</button>
</form>
Incorrect: hidden input with multiple aria-* attributes
<form action="/save" method="post">
<input
type="hidden"
name="session_token"
value="abc123"
aria-label="Session token"
aria-required="true"
aria-describedby="token-help">
<button type="submit">Save</button>
</form>
Correct: all aria-* attributes removed
<form action="/save" method="post">
<input type="hidden" name="session_token" value="abc123">
<button type="submit">Save</button>
</form>
Correct: aria-* attributes on a visible input (where they belong)
If the input is meant to be visible and accessible, use an appropriate type value instead of "hidden":
<form action="/login" method="post">
<label for="username">Username</label>
<input
type="text"
id="username"
name="username"
aria-required="true"
aria-invalid="false"
aria-describedby="username-help">
<p id="username-help">Enter your registered email or username.</p>
<button type="submit">Log in</button>
</form>
The hidden attribute indicates that an element is not yet, or is no longer, relevant to the current state of the page. Browsers will not render elements that have this attribute. It’s available on all HTML elements as a global attribute.
In HTML, boolean attributes like hidden, disabled, readonly, and checked follow special rules. Unlike attributes in programming languages where you might set a value to true or false, boolean attributes in HTML work by presence or absence:
- Present = the feature is on (e.g., hidden, hidden="", or hidden="hidden")
- Absent = the feature is off (the attribute is simply not in the markup)
This is a common source of confusion. Writing hidden="false" does not make the element visible. Because the attribute is still present in the markup, the browser interprets it as “this element is hidden.” The actual string value "false" is ignored for the purpose of determining the boolean state. This can lead to frustrating bugs where elements remain invisible despite what looks like correct code.
According to the HTML specification, the only valid values for a boolean attribute are the empty string ("") or the attribute’s own name (e.g., hidden="hidden"). Any other value, including "true" or "false", is invalid and will trigger a W3C validator error.
How the hidden attribute works with newer values
Starting with more recent updates to the HTML specification, the hidden attribute also accepts the value "until-found". When set to hidden="until-found", the element remains hidden but can be revealed by the browser’s find-in-page feature or by fragment navigation. This is the only keyword value (besides the empty string and the attribute’s canonical name) that changes the attribute’s behavior. It does not change the fact that "false" is an invalid value.
How to fix it
- To hide an element, add the hidden attribute with no value.
- To show an element, remove the hidden attribute entirely from the markup.
- If you’re toggling visibility with JavaScript, use element.hidden = false (the JavaScript property, not the HTML attribute) or element.removeAttribute('hidden').
Examples
❌ Invalid: setting hidden to "false"
<!-- The element is STILL hidden and the markup is invalid -->
<div hidden="false">You won't see this text.</div>
❌ Invalid: setting hidden to "true"
<!-- "true" is also not a valid value for a boolean attribute -->
<p hidden="true">This paragraph is hidden, but the markup is invalid.</p>
✅ Valid: using hidden without a value
<div hidden>This element is hidden from the page.</div>
✅ Valid: using hidden with an empty string or its own name
<!-- Both of these are valid ways to write boolean attributes -->
<div hidden="">Hidden element</div>
<div hidden="hidden">Also a hidden element</div>
✅ Valid: showing the element by omitting hidden
<div>This element is visible because it has no hidden attribute.</div>
✅ Valid: using hidden="until-found"
<div hidden="until-found">
This content is hidden but can be found via browser search.
</div>
Toggling visibility with JavaScript
When dynamically showing or hiding elements, use the hidden property on the DOM element rather than setting the attribute to "false":
<button type="button" id="toggle">Toggle message</button>
<p id="message" hidden>Hello! Now you can see me.</p>
<script>
document.getElementById("toggle").addEventListener("click", function () {
const msg = document.getElementById("message");
msg.hidden = !msg.hidden; // Correctly toggles the boolean property
});
</script>
Using msg.hidden = false in JavaScript correctly removes the hidden attribute from the element. This is different from writing hidden="false" directly in HTML, which keeps the attribute present and triggers the validation error.
An <input type="hidden"> element is inherently invisible to all users. It is not rendered on the page, it cannot receive focus, and browsers automatically exclude it from the accessibility tree. The aria-hidden attribute is designed to hide visible content from assistive technologies like screen readers, but applying it to an element that is already fully hidden serves no purpose.
The HTML specification explicitly forbids the use of aria-hidden on hidden inputs. This restriction exists because combining the two is semantically meaningless — you cannot “hide from assistive technologies” something that is already invisible to everyone. Validators flag this as an error to encourage clean, standards-compliant markup and to help developers avoid misunderstandings about how ARIA attributes interact with native HTML semantics.
This issue commonly arises when aria-hidden="true" is applied broadly to a group of elements (for example, via a script or template) without checking whether specific children already handle their own visibility. It can also happen when developers add ARIA attributes as a precaution, not realizing that the native behavior of type="hidden" already covers accessibility concerns.
To fix this, remove the aria-hidden attribute from any <input> element whose type is hidden. No replacement is needed — the browser already handles everything correctly.
Examples
Incorrect
Adding aria-hidden to a hidden input triggers a validation error:
<form action="/submit" method="post">
<input type="hidden" aria-hidden="true" name="month" value="10">
<input type="hidden" aria-hidden="true" name="csrf_token" value="abc123">
<button type="submit">Submit</button>
</form>
Correct
Remove the aria-hidden attribute entirely. The hidden inputs are already inaccessible to all users by default:
<form action="/submit" method="post">
<input type="hidden" name="month" value="10">
<input type="hidden" name="csrf_token" value="abc123">
<button type="submit">Submit</button>
</form>
When aria-hidden is appropriate
The aria-hidden attribute is intended for elements that are visually present but should be hidden from assistive technologies, such as decorative icons:
<button type="button">
<span aria-hidden="true">★</span>
Favorite
</button>
In this case, the decorative star is visible on screen but irrelevant to screen reader users, so aria-hidden="true" correctly prevents it from being announced. This is the proper use case — hiding visible content from the accessibility tree, not redundantly marking already-hidden elements.
Ready to validate your sites?
Start your free trial today.