feat(login): add show/hide password toggle on the sign-in form #328

Open
opened 2026-04-24 13:27:27 +02:00 by marcel · 0 comments
Owner

Context

/login has no password visibility toggle. Standard UX improvement, low effort. Mostly helps family members on shared devices who want to verify they typed the password correctly — especially relevant given the 60+ transcriber persona who benefits from any friction reduction.

Non-goals

  • No other login flow changes (no "remember me", no magic-link, no SSO).
  • No password strength meter.
  • No auto-fill behaviour tweaks.

Proposed design

Eye-icon button sits inside the right edge of the password field:

┌──────────────────────────────────────┐
│ ••••••••                          👁 │
└──────────────────────────────────────┘
  • Icon: eye (password hidden) / eye-off (password visible). Reuse existing icon set (the app already has SVG icons for other controls).
  • Click toggles the <input> between type="password" and type="text".
  • Button is type="button" — must NOT submit the form.
  • aria-label toggles between "Passwort anzeigen" and "Passwort verbergen".
  • aria-pressed reflects current state ("true" when password is visible).
  • Touch target ≥ 44 × 44 (WCAG 2.5.5).
  • Focusable with keyboard; focus ring matches existing form conventions.

Implementation plan

Frontend

  • Modify frontend/src/routes/login/+page.svelte:
    • Wrap the password input in a relative container.
    • Add a small toggle button absolutely positioned to the right.
    • Local reactive state $state for showPassword; bind type accordingly.
  • Reuse the eye / eye-off SVG icons already in the icon library (or add if not present).

i18n

2 new Paraglide keys:

  • login_show_password → "Passwort anzeigen" / "Show password" / "Mostrar contraseña"
  • login_hide_password → "Passwort verbergen" / "Hide password" / "Ocultar contraseña"

Tests

  • Component: default state type="password". Click toggle → type="text" + aria-label flips + aria-pressed="true". Click again → back to hidden.
  • Component: button has type="button" (does not submit parent form).
  • E2E: login flow unchanged with toggle visible. Type password, click toggle to verify, click back, submit, land on home.

Acceptance criteria

  • Toggle button inside the password field
  • Icon + aria-label + aria-pressed reflect current state
  • Button does not submit the form
  • Keyboard-focusable with visible focus ring
  • Touch target ≥ 44 × 44
  • i18n complete for de/en/es
  • Login happy path unaffected

Critical files

frontend/src/routes/login/+page.svelte
frontend/messages/{de,en,es}.json
## Context `/login` has no password visibility toggle. Standard UX improvement, low effort. Mostly helps family members on shared devices who want to verify they typed the password correctly — especially relevant given the 60+ transcriber persona who benefits from any friction reduction. ## Non-goals - No other login flow changes (no "remember me", no magic-link, no SSO). - No password strength meter. - No auto-fill behaviour tweaks. ## Proposed design Eye-icon button sits inside the right edge of the password field: ``` ┌──────────────────────────────────────┐ │ •••••••• 👁 │ └──────────────────────────────────────┘ ``` - Icon: eye (password hidden) / eye-off (password visible). Reuse existing icon set (the app already has SVG icons for other controls). - Click toggles the `<input>` between `type="password"` and `type="text"`. - Button is `type="button"` — must NOT submit the form. - `aria-label` toggles between "Passwort anzeigen" and "Passwort verbergen". - `aria-pressed` reflects current state ("true" when password is visible). - Touch target ≥ 44 × 44 (WCAG 2.5.5). - Focusable with keyboard; focus ring matches existing form conventions. ## Implementation plan ### Frontend - Modify `frontend/src/routes/login/+page.svelte`: - Wrap the password input in a relative container. - Add a small toggle button absolutely positioned to the right. - Local reactive state `$state` for `showPassword`; bind `type` accordingly. - Reuse the eye / eye-off SVG icons already in the icon library (or add if not present). ### i18n 2 new Paraglide keys: - `login_show_password` → "Passwort anzeigen" / "Show password" / "Mostrar contraseña" - `login_hide_password` → "Passwort verbergen" / "Hide password" / "Ocultar contraseña" ## Tests - **Component:** default state `type="password"`. Click toggle → `type="text"` + `aria-label` flips + `aria-pressed="true"`. Click again → back to hidden. - **Component:** button has `type="button"` (does not submit parent form). - **E2E:** login flow unchanged with toggle visible. Type password, click toggle to verify, click back, submit, land on home. ## Acceptance criteria - [ ] Toggle button inside the password field - [ ] Icon + `aria-label` + `aria-pressed` reflect current state - [ ] Button does not submit the form - [ ] Keyboard-focusable with visible focus ring - [ ] Touch target ≥ 44 × 44 - [ ] i18n complete for de/en/es - [ ] Login happy path unaffected ## Critical files ``` frontend/src/routes/login/+page.svelte frontend/messages/{de,en,es}.json ```
marcel added the P3-laterfeatureui labels 2026-04-24 13:28:17 +02:00
Sign in to join this conversation.
No Label P3-later feature ui
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#328