Password Reveal
stimeo--password-reveal
Toggles a password field between masked and visible, preserving focus.
The stimeo--password-reveal controller switches the input's type between password and text, keeping the toggle button's aria-pressed and the data-state in sync. The accessible name stays state-independent (Show password) while aria-pressed conveys the state. When the input itself was focused its focus and caret are restored across the type change; when the toggle button holds focus it is left alone. An optional autoHide re-masks after a delay. Behavior only — icon rendering is owned by this Playground.
Keyboard
| Key | Action |
|---|---|
| Enter / Space | Toggle masked / visible (native button). |
<%# Markup for the password-reveal demo.
The toggle switches the input's type between password ↔ text and syncs aria-pressed /
data-state. If the input was focused, focus and caret position are preserved. The eye
icon rendering switches on aria-pressed in demo.css. %>
<div class="password-reveal" data-controller="stimeo--password-reveal">
<label class="password-reveal__label" for="password-reveal-demo-input">
<%= t("components.password_reveal.demo.label") %>
</label>
<div class="password-reveal__field">
<input
class="password-reveal__input"
id="password-reveal-demo-input"
type="password"
value="hunter2"
autocomplete="current-password"
data-stimeo--password-reveal-target="input">
<button
class="password-reveal__toggle"
type="button"
aria-pressed="false"
aria-label="<%= t('components.password_reveal.demo.show') %>"
data-stimeo--password-reveal-target="toggle"
data-action="click->stimeo--password-reveal#toggle">
<span class="password-reveal__icon" aria-hidden="true"></span>
</button>
</div>
</div>
/*
* Presentation-only styles for the password-reveal demo.
* The open/closed eye icon switches on the toggle's aria-pressed (set by the library).
*/
.password-reveal {
max-width: 20rem;
}
.password-reveal__label {
display: block;
margin-bottom: 0.25rem;
font-weight: 600;
}
.password-reveal__field {
display: flex;
align-items: center;
border: 1px solid var(--border-strong);
border-radius: 0.375rem;
background: var(--surface-card);
}
.password-reveal__input {
flex: 1;
padding: 0.5rem 0.75rem;
border: 0;
background: transparent;
font: inherit;
color: var(--fg);
}
.password-reveal__input:focus {
outline: none;
}
.password-reveal__field:focus-within {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
.password-reveal__toggle {
display: grid;
place-items: center;
width: 2.25rem;
height: 2.25rem;
border: 0;
background: transparent;
cursor: pointer;
color: var(--color-text-muted);
}
/* While masked (aria-pressed="false") show the eye icon; while revealed, the eye with a slash. */
.password-reveal__icon::before {
content: "👁";
font-size: 1.1rem;
}
.password-reveal__toggle[aria-pressed="true"] .password-reveal__icon::before {
content: "🙈";
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--password-reveal"
Targets
| Name | Description | Attribute |
|---|---|---|
input
required
|
The password field whose type toggles between password and text. |
data-stimeo--password-reveal-target="input" |
toggle
required
|
The show/hide button; its aria-pressed reflects the revealed state. |
data-stimeo--password-reveal-target="toggle" |
Values
| Name | Description | Attribute |
|---|---|---|
autoHide
|
Delay (ms) after which a revealed input re-masks; 0 (default) disables it. | data-stimeo--password-reveal-auto-hide-value |
Actions
| Name | Description | Action |
|---|---|---|
toggle
|
Switches the input between masked and revealed, preserving focus and caret. | stimeo--password-reveal#toggle |
Events
| Name | Description | Event |
|---|---|---|
toggle
|
Dispatched on each toggle, with the new visible boolean in detail. |
stimeo--password-reveal:toggle |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
aria-pressed |
Toggle | "true" when revealed, "false" when masked. |
data-state |
Root element | "hidden" / "visible". |
type |
Input | "password" / "text". |