Accessibility and Frontend Security
AdvancedSemantic HTML gets you most of accessibility for free, and most XSS comes from one habit. Both are asked in interviews and both are visible in code review.
Overview
These two subjects sit together because both are judged on defaults rather than heroics. Accessibility is mostly a consequence of using the right element — a button that is a button is keyboard-operable, focusable and announced correctly with no work at all, while a clickable div needs four attributes and a key handler to reach the same place. Frontend security is similarly concentrated: the large majority of vulnerabilities come from injecting untrusted content into the page or storing tokens where any script can read them. Knowing the small set of defaults covers most of what a reviewer or an interviewer will look for.
Semantic HTML
The right element does the work. This is the highest-leverage accessibility decision there is.
// A clickable div needs all of this to match a button
<div onClick={h} role="button" tabIndex={0}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && h()}>
// A button just works
<button onClick={h}>Run</button>
// Elements that carry meaning for free
<nav> <main> <header> <footer> <aside>
<button> <a href> <label> <fieldset> <table>
// Labels — every input needs one
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" />
// An icon-only control needs an accessible name
<button aria-label="Close dialog"><X aria-hidden="true" /></button>
// Images: alt describes purpose; decorative images take alt=""
<img src={cover} alt="" />
// Headings are a document outline, not font sizes.
// One h1, no skipped levels — a screen-reader user navigates by them.Keyboard, Focus and ARIA
Everything reachable by mouse must be reachable by keyboard. ARIA is a last resort, not a first one.
// Tab through your page. If you cannot complete a flow, it is broken.
// Never remove the focus ring — restyle it
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px }
// Modals need three things:
// 1. focus moves into the dialog on open
// 2. focus is trapped while it is open
// 3. focus returns to the trigger on close
// plus Escape to close, and aria-modal="true"
// Radix, React Aria and Headless UI do all of this — use them.
// Announce async updates a sighted user sees but nobody hears
<div role="status" aria-live="polite">{message}</div>
<div role="alert">{error}</div> // interrupts, for errors
// The first rule of ARIA is not to use ARIA:
<div role="button"> // needs tabIndex and key handling
<button> // already correct
// Wrong ARIA is worse than none — aria-hidden on a focusable
// element creates a control a screen reader cannot see but can land on.
// Check it: axe DevTools, Lighthouse, eslint-plugin-jsx-a11y.
// Automated tools find roughly a third; keyboard-test the rest.XSS, CSRF and Headers
The short list that covers most frontend vulnerabilities.
// XSS — injecting untrusted content into the page
element.innerHTML = comment // vulnerable
<div dangerouslySetInnerHTML={{ __html: comment }} /> // vulnerable
element.textContent = comment // safe
<div>{comment}</div> // React escapes by default
// If you must render HTML, sanitise it
import DOMPurify from 'dompurify'
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />
// href is an injection point too
<a href={userUrl}> // 'javascript:...' executes
// Validate the protocol is http/https before rendering.
// CSRF — an httpOnly cookie is sent automatically, including from
// another site's form. SameSite=Lax blocks most of it; state-changing
// requests should also carry a CSRF token.
// Headers, set once, that block whole classes of attack
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000
// And the recurring one: never put a secret in client code.
// NEXT_PUBLIC_ anything is published.Key Points to Remember
- 1A native button, label or nav brings keyboard support, focus and screen-reader semantics for free
- 2Every interactive control must be reachable and operable by keyboard, with a visible focus style
- 3ARIA is a last resort — incorrect ARIA is worse than none, and automated tools catch only about a third of issues
- 4React escapes interpolated text; innerHTML and dangerouslySetInnerHTML are the XSS entry points, so sanitise with DOMPurify
- 5SameSite cookies plus a CSRF token cover CSRF, and a Content-Security-Policy header blocks whole classes of injection
Interview Questions
Sign in to ask AriaWhy is a <button> better than a clickable <div>?
How does XSS happen in a React app, given that React escapes by default?
What must a modal dialog do to be accessible?
Ask Aria about Accessibility and Frontend Security
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.