Browser Tech
February - March 2026
UX/UI design · Front-end development
VS Code · HTML/CSS/JS
Context
For this course I had to build an inheritance tax form, styled after NS (Dutch Railways). The core requirement: the form had to work fully without Javascript, but become better with it — a concept known as progressive enhancement.
There was also a strong focus on usability and accessibility: the form had to work for everyone, including people who only use a keyboard or a screen reader.
Approach & Process
Week 1
Orientation & HTML foundation
Read articles about forms, attended validation workshops. Set up the first HTML structure using fieldset.
Week 2
Styling & progressive disclosure
Built out the CSS in NS style. Questions expand and collapse based on previous answers — working without Javascript using CSS nesting.
Week 3
Second pattern & validation
Built the second form pattern: adding and individually removing beneficiaries. Added custom JavaScript validation using aria-invalid, aria-describedby and aria-live.
Week 4
Refinement & extra features
Local storage & reset confirmation via dialog, dark/light mode, unlimited beneficiaries via innerHTML, improved radio button styling and keyboard accessibility.
Progressive disclosure — no Javascript required
Follow-up questions expand and collapse based on previous answers. So it functions even when Javascript is disabled, ensuring no user is locked out of the form flow.
Screen reader-friendly validation
Error messages are announced to screen readers using aria-live="polite" and linked to their inputs via aria-describedby. Invalid fields are flagged with aria-invalid="true", and visual errors are powered by :user-invalid in CSS — so feedback is clear for both sighted and non-sighted users.
Contextual tooltips with <details>
Clarifying information for complex questions is tucked inside native <details> elements. These are keyboard-accessible and semantic, requiring no extra Javascript or ARIA tricks.
Keyboard accessibility for radio buttons
Hiding radio buttons with display:none makes them invisible to keyboards and screen readers. I fixed this using position: absolute with width/height: 0, keeping them in the DOM while adding a clearly visible focus state.
Safe reset with <dialog> confirmation
Resetting a long form by accident is frustrating. A native <dialog> element asks for confirmation before clearing all data, protecting users from losing their progress.
Autocomplete with <datalist>
Certain fields use a native <datalist> element to suggest options as the user types. This reduces input errors and speeds up form completion without any custom Javascript — and it works with screen readers and keyboard navigation out of the box.
Reflection
Building forms is much harder than I expected. There's a lot more to usability, validation and accessibility than just putting a few inputs on a page.
This was a genuinely challenging project that pushed me well outside my comfort zone. Combining accessibility, validation and progressive enhancement all at once was entirely new to me. Looking back, I'm proud of what I built — and I'll never underestimate forms again.