{"checkpoints":{"s-a11y-1":[{"q":"<p>A Ticketly manager says: “Only 2% of our customers told us they are disabled, so accessibility can wait.” What is the strongest response?</p>","options":[{"text":"Disability is under-reported, temporary and situational limits affect far more people, and selling to EU customers brings legal duties","why":"Correct. Around one in six people has a significant disability, many never disclose it, and the same fixes help people with broken wrists, glare or slow connections."},{"text":"Agree, because WCAG only applies when more than 5% of users are disabled","why":"WCAG has no usage threshold. It describes the content, not the audience size."},{"text":"Agree, but add an accessibility overlay script to be safe","why":"Overlays don’t fix the underlying markup, and the default page stays broken for the people who need it most."}],"answer":0},{"q":"<p>Karim uses a single switch. The scanning software steps through Ticketly’s controls but never stops on the seat map’s “Select” control, a div with a click handler. Why?</p>","options":[{"text":"Switch software only works on mobile devices","why":"Switch access works on desktop and mobile. The problem is the element, not the platform."},{"text":"The div needs a larger font size","why":"Size doesn’t affect whether scanning stops on an element; focusability does."},{"text":"Switch users can only press links, not buttons","why":"Switch software can activate any focusable control, buttons included."},{"text":"Switch scanning moves between focusable elements, and a div with only a click handler isn’t focusable","why":"Correct. Switch users depend on the same keyboard operability as everyone else. A real button fixes it."}],"answer":3},{"q":"<p>Ticketly’s “Need help?” link sits in the header on most pages but moves into the footer on the checkout steps. Which WCAG 2.2 criterion is at risk?</p>","options":[{"text":"2.4.11 Focus Not Obscured (Minimum)","why":"That criterion is about focused elements being hidden behind other content, not about where help appears."},{"text":"3.2.6 Consistent Help","why":"Correct. New in 2.2 at Level A: help mechanisms repeated across pages must appear in the same relative order."},{"text":"3.3.7 Redundant Entry","why":"Redundant Entry is about not asking users to re-enter information they already gave."},{"text":"2.5.8 Target Size (Minimum)","why":"Target size concerns how big a control is, not where it is placed across pages."}],"answer":1},{"q":"<p>A button shows a bin icon and the visible text “Delete ticket”, but NVDA announces “Remove, button”. What explains this?</p>","options":[{"text":"NVDA shortens long button text automatically","why":"Screen readers read the accessible name as it is; they don’t shorten or paraphrase it."},{"text":"The bin icon’s alt text is read instead of the text","why":"If the icon had alt text it would be added to the content, not replace it."},{"text":"An aria-label=“Remove” overrides the visible text, which also breaks Label in Name for voice control users","why":"Correct. aria-label replaces the content as the name. Remove it, or make it start with “Delete ticket”."},{"text":"The button is missing a title attribute","why":"title is the last fallback and wouldn’t override anything; the announced name comes from a higher-priority source."}],"answer":2},{"q":"<p>Ticketly is a 40-person company based outside the EU that sells festival tickets online to customers in Germany. Does the European Accessibility Act matter to it?</p>","options":[{"text":"Yes; e-commerce services offered to EU consumers are in scope, and the microenterprise exemption only covers fewer than 10 staff","why":"Correct. Since 28 June 2025 the EAA applies to covered services offered in the EU, wherever the company is based."},{"text":"No, because the company isn’t based in the EU","why":"The EAA follows where services are offered to consumers, not where the company is registered."},{"text":"No, because event tickets are not covered by any accessibility law","why":"E-commerce is one of the EAA’s covered services, and transport ticketing is covered too."}],"answer":0}],"s-a11y-2":[{"q":"<p>Ticketly’s site search form sits in the header. Which markup exposes it as a search landmark?</p>","options":[{"text":"<code dir=\"ltr\">&lt;div class=&quot;search&quot;&gt;&lt;form&gt;…&lt;/form&gt;&lt;/div&gt;</code>","why":"A div with a class has no landmark role, so it doesn’t appear in the landmarks list."},{"text":"<code dir=\"ltr\">&lt;form&gt;…&lt;/form&gt;</code> with no name","why":"A form becomes a landmark only when it has an accessible name, and even then it is a form landmark, not search."},{"text":"<code dir=\"ltr\">&lt;nav class=&quot;search&quot;&gt;…&lt;/nav&gt;</code>","why":"nav is for navigation links. Using it for search would mislabel the region."},{"text":"<code dir=\"ltr\">&lt;search&gt;&lt;form&gt;…&lt;/form&gt;&lt;/search&gt;</code>","why":"Correct. The search element maps to the search landmark. On older code you will also see form role=“search”."}],"answer":3},{"q":"<p>A “Download your tickets (PDF)” control fetches the file at /bookings/123/tickets.pdf. Which element is right?</p>","options":[{"text":"A link: <code dir=\"ltr\">&lt;a href=&quot;/bookings/123/tickets.pdf&quot;&gt;Download your tickets (PDF, 200 KB)&lt;/a&gt;</code>","why":"Correct. It goes to a resource with a URL, so it is a link. Saying the file type and size sets expectations."},{"text":"A button that calls fetch() and opens the file","why":"Recreating navigation with a script loses link behaviour such as opening in a new tab or copying the address."},{"text":"A div styled as a button with role=“link”","why":"That needs tabindex and key handling to work, and a real anchor already does it all."}],"answer":0},{"q":"<p>The checkout asks for date of birth as three inputs (day, month, year) under one visible text “Date of birth”. What is the best markup?</p>","options":[{"text":"One label element with for pointing at the day input","why":"A label can only name one control, so month and year would be unnamed."},{"text":"aria-label=“Date of birth” on all three inputs","why":"All three would get the same name, so users couldn’t tell day from month from year."},{"text":"A fieldset with legend “Date of birth”, and labels Day, Month and Year with autocomplete bday-day, bday-month and bday-year","why":"Correct. The legend names the group, each field has its own label, and autofill works."}],"answer":2},{"q":"<p><code dir=\"ltr\">&lt;button&gt;&lt;img src=&quot;calendar.svg&quot; alt=&quot;calendar&quot;&gt;&lt;/button&gt;</code> adds the event to the user’s calendar. What should change?</p>","options":[{"text":"Nothing; the button has a name","why":"It has a name, but “calendar” describes the picture, not what pressing the button does."},{"text":"The alt should describe the action, such as “Add to calendar”","why":"Correct. For functional images, alt text names the action or destination."},{"text":"The alt should be empty because icons are decorative","why":"This icon is the button’s only content, so an empty alt would leave the button with no name at all."},{"text":"The image should get role=“button”","why":"The button element already supplies the role. The problem is the name."}],"answer":1},{"q":"<p>Ticketly’s festival schedule is a table with stage names across the top and times down the first column. What makes each cell announce its time and stage?</p>","options":[{"text":"Bold text in the first column and first row","why":"Bold is visual only and isn’t exposed as header information."},{"text":"A summary paragraph above the table","why":"A summary helps orientation but doesn’t associate headers with each cell."},{"text":"role=“grid” on the table","why":"grid is for interactive, spreadsheet-like widgets and adds keyboard expectations a schedule doesn’t need."},{"text":"th scope=“col” for the stages, th scope=“row” for the times, and a caption","why":"Correct. Screen readers then announce the row and column headers as users move between cells."}],"answer":3}],"s-a11y-3":[{"q":"<p><code dir=\"ltr\">&lt;div class=&quot;card&quot; tabindex=&quot;0&quot; onclick=&quot;openEvent()&quot;&gt;</code> receives focus, but pressing Enter does nothing. Why?</p>","options":[{"text":"tabindex only makes it focusable; keyboard activation isn’t wired, because Enter doesn’t fire click on a div","why":"Correct. Use a link (it opens an event page) and you get focus, Enter and the right role for free."},{"text":"The onclick attribute only works with a mouse in some browsers","why":"onclick fires for real clicks in every browser; it is just never triggered by keys on a div."},{"text":"tabindex must be 1 for Enter to work","why":"Positive tabindex only changes focus order and causes ordering bugs. It has nothing to do with activation."}],"answer":0},{"q":"<p>The booking dialog’s custom close button removes the dialog element from the DOM. Afterwards, keyboard focus jumps to the top of the page. What is the best fix?</p>","options":[{"text":"Add tabindex=“-1” to the body so focus has somewhere to go","why":"Focus already falls back to the body. The problem is that it should go back to the control that opened the dialog."},{"text":"Add aria-live to the dialog so the closing is announced","why":"An announcement doesn’t put the user back where they were."},{"text":"Close it with dialog.close() so the browser restores focus to the opener, or focus the opener explicitly before removing anything","why":"Correct. Users continue from where they started instead of re-tabbing through the page."},{"text":"Remove the close button and rely on Escape only","why":"Many users don’t know about Escape, and touch users have no Escape key."}],"answer":2},{"q":"<p>As the user types in Ticketly’s search box, a count such as “12 events found” updates. What is the best way to announce it?</p>","options":[{"text":"Move focus to the count after every keystroke","why":"That would pull the user out of the field they are typing in."},{"text":"A role=“status” element present from page load, updated once typing pauses","why":"Correct. A polite live region announces the count without moving focus, and waiting for a pause avoids a flood of announcements."},{"text":"role=“alert” on the count so it is never missed","why":"Assertive announcements on every keystroke interrupt the user’s own typing echo, which is exhausting."},{"text":"Put the count in the input’s placeholder","why":"The placeholder isn’t announced on change and disappears while the user types."}],"answer":1},{"q":"<p>In a tablist, arrow keys move focus between tabs, but the panel only changes when the user presses Enter or Space. Is that a valid implementation of the APG tabs pattern?</p>","options":[{"text":"No, the APG requires panels to change as soon as a tab receives focus","why":"The APG describes both automatic and manual activation."},{"text":"No, tabs must be activated with the Tab key","why":"Tab moves out of the tablist into the panel. Arrow keys move between tabs."},{"text":"Only if each tab is also a link","why":"Tabs aren’t links; links to other pages are navigation, not a tab widget."},{"text":"Yes; this is manual activation, recommended when showing a panel is slow, for example because it loads data","why":"Correct. Automatic activation suits instant panels; manual avoids loading every panel the user arrows past."}],"answer":3},{"q":"<p><code dir=\"ltr\">&lt;button aria-controls=&quot;events-menu&quot;&gt;Events&lt;/button&gt;</code> and <code dir=\"ltr\">&lt;ul id=&quot;events-menu&quot; aria-expanded=&quot;true&quot;&gt;</code>. NVDA never says “expanded” on the button. Why?</p>","options":[{"text":"aria-expanded belongs on the button that controls the content, not on the list","why":"Correct. The control carries the state; move the attribute and update it on each toggle."},{"text":"aria-controls must be removed for aria-expanded to work","why":"aria-controls is optional, but it doesn’t stop aria-expanded from working."},{"text":"aria-expanded only works on elements with role=“menu”","why":"aria-expanded is supported on buttons, links, comboboxes and more. Disclosure buttons use it all the time."}],"answer":0}],"s-a11y-4":[{"q":"<p>A Ticketly section heading is 24px, regular weight, with a contrast ratio of 3.2:1. Does it meet 1.4.3 at Level AA?</p>","options":[{"text":"No, all text needs 4.5:1","why":"Large text has a lower threshold, because bigger letters are easier to read at lower contrast."},{"text":"No, headings need 7:1","why":"7:1 is the AAA threshold for normal text; it isn’t required at AA."},{"text":"Yes; 24px counts as large text, which needs 3:1","why":"Correct. Large text is at least 24px regular or 18.66px bold, and needs 3:1."},{"text":"Yes, because headings are exempt from contrast requirements","why":"Headings are text and are covered. They pass here because of their size, not an exemption."}],"answer":2},{"q":"<p>At a 320px viewport, Ticketly’s page reflows, but the wide festival schedule table scrolls horizontally inside its own container. Does this fail 1.4.10 Reflow?</p>","options":[{"text":"No; content that needs two dimensions, like data tables, is exempt, as long as the rest of the page reflows","why":"Correct. Keep the scrolling to the table’s container (and make that container keyboard scrollable) rather than the whole page."},{"text":"Yes; nothing may ever scroll horizontally","why":"The criterion explicitly exempts content that requires a two-dimensional layout."},{"text":"Yes, unless the table is replaced with an image","why":"An image of a table would remove the data from screen readers and fail other criteria."}],"answer":0},{"q":"<p>What is the accessible name of the search input?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">input</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> id</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"q\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> placeholder</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Search events\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> aria-labelledby</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"go\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> id</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"go\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Search&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n","options":[{"text":"“Search events”","why":"The placeholder is only a last resort, used when nothing else provides a name."},{"text":"No name, because aria-labelledby can’t point at a button","why":"aria-labelledby can reference any element with text."},{"text":"“Search events Search”","why":"Names don’t combine sources; the highest-priority source wins."},{"text":"“Search”","why":"Correct. aria-labelledby has the highest priority, so the button’s text becomes the input’s name."}],"answer":3},{"q":"<p>Ticketly’s hero uses a parallax effect: the background moves at a different speed when scrolling. A user has set Reduce motion in their operating system. What should happen?</p>","options":[{"text":"Nothing; parallax is triggered by the user’s own scrolling, so it is acceptable","why":"Motion triggered by interaction can still cause dizziness; that is exactly what reduced motion preferences are for."},{"text":"Inside a prefers-reduced-motion: reduce media query, turn the parallax off and show a static background","why":"Correct. The content stays, and the large movement that can trigger vestibular symptoms goes."},{"text":"Show a dialog asking whether they want animations","why":"The user has already answered in their system settings. Respect the preference without asking again."}],"answer":1},{"q":"<p>Ticketly launches a fully Arabic version of its site. What belongs on the root element?</p>","options":[{"text":"<code dir=\"ltr\">&lt;html lang=&quot;en&quot; dir=&quot;rtl&quot;&gt;</code>","why":"The language would still be English, so screen readers would use an English voice for Arabic text."},{"text":"<code dir=\"ltr\">&lt;html lang=&quot;ar&quot;&gt;</code> only, with direction: rtl in CSS","why":"Direction is part of the content’s meaning and belongs in the markup, not only in a stylesheet."},{"text":"<code dir=\"ltr\">&lt;html dir=&quot;auto&quot;&gt;</code>","why":"auto is for text of unknown direction such as user input. For a known Arabic page, state it, along with the language."},{"text":"<code dir=\"ltr\">&lt;html lang=&quot;ar&quot; dir=&quot;rtl&quot;&gt;</code>","why":"Correct. lang selects the Arabic voice and other language features; dir sets the base direction for the whole page."}],"answer":3}],"s-a11y-5":[{"q":"<p>axe marks the contrast of white text over the festival photo as “needs review” rather than a violation. What should you do?</p>","options":[{"text":"Check it manually against the lightest part of the photo behind the text, and add an overlay if it fails","why":"Correct. axe can’t know which pixels are behind the text, so a person must measure it."},{"text":"Ignore it, since it isn’t a violation","why":"“Needs review” means the tool couldn’t decide, not that the content passed."},{"text":"Disable the color-contrast rule so the report stays clean","why":"That hides every future contrast failure on the site, not only this one."}],"answer":0},{"q":"<p>While testing a form with NVDA, typing the letter “h” in a text field jumps to the next heading instead of typing. What is happening?</p>","options":[{"text":"The field is read-only","why":"A read-only field wouldn’t make NVDA jump to headings; it would simply not accept input."},{"text":"NVDA’s keyboard layout is broken and needs reinstalling","why":"Nothing is broken. This is how browse mode is designed to work."},{"text":"NVDA is still in browse mode, where letters are navigation keys; press Enter or NVDA+Space to switch to focus mode","why":"Correct. If NVDA never switches automatically, check that the field is a real input and not a custom element without a role."},{"text":"The page has too many headings","why":"The number of headings has no effect on whether letters are typed."}],"answer":2},{"q":"<p>Your first Playwright and axe run on Ticketly reports 340 violations across the site. What is the most effective next step?</p>","options":[{"text":"Turn the scan off until there is time to fix everything","why":"Without the scan, new violations are added every week, so the backlog only grows."},{"text":"Fix the violations in the order axe lists them","why":"axe’s order isn’t a priority order. Impact on real tasks should decide."},{"text":"Add aria-label attributes wherever axe complains","why":"Adding ARIA to silence a tool often creates new problems, such as names that don’t match visible labels."},{"text":"Record the current violations as a baseline, fail CI only on new ones, and fix the baseline starting with the checkout flow","why":"Correct. The baseline stops regressions immediately while the existing debt is paid down by impact."}],"answer":3},{"q":"<p>Which audit finding should be rated critical?</p>","options":[{"text":"A decorative divider announced as “graphic”","why":"This adds noise but doesn’t stop anyone completing a task, so it is minor."},{"text":"A keyboard trap inside the embedded payment form","why":"Correct. Keyboard users can’t finish paying or leave the form, which blocks the most important task on the site."},{"text":"Footer link text that says “More”","why":"Vague link text is a real issue, but it rarely blocks a task. It is moderate at most."},{"text":"Grey footer text at 4.2:1 contrast","why":"It fails 1.4.3 and should be fixed, but it doesn’t block a key task, so it isn’t critical."}],"answer":1},{"q":"<p>The vendor of Ticketly’s live-chat widget says it is “fully WCAG compliant”. What should you do?</p>","options":[{"text":"Ask for their Accessibility Conformance Report, and include the widget in your own keyboard and screen reader testing","why":"Correct. Barriers in third-party widgets are your users’ barriers, and claims are only as good as their testing."},{"text":"Accept the claim, since vendors are legally responsible for their widgets","why":"On your site, your users meet the widget’s barriers, and you may share responsibility for them."},{"text":"Exclude the widget from your audit scope to keep the report focused","why":"Leaving out a feature people use to get help hides a part of the experience that may be inaccessible."}],"answer":0}]},"final":[{"q":"<p>Which change fixes the most problems at once?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"link\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> onclick</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">go</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">('/faq')\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>FAQ&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n","options":[{"text":"Add tabindex=“0”","why":"That makes it focusable, but it still has no link role, doesn’t respond to Enter, and can’t be opened in a new tab."},{"text":"Add role=“link”","why":"The role changes the announcement only; it is still unfocusable and has no keyboard support."},{"text":"Add aria-label=“FAQ”","why":"The span already has the text FAQ. A label on a generic span is ignored and fixes nothing."},{"text":"Replace it with <code dir=\"ltr\">&lt;a href=&quot;/faq&quot;&gt;FAQ&lt;/a&gt;</code>","why":"Correct. A real link brings the role, focus, Enter activation, new-tab support and works without JavaScript."}],"answer":3},{"q":"<p>Ticketly’s buttons use white 14px text on #5b3cc4, a ratio of 7.27:1. How does this rate against WCAG contrast criteria?</p>","options":[{"text":"It fails AA, because small text needs 10:1","why":"There is no 10:1 threshold. AA needs 4.5:1 for normal text."},{"text":"It passes AA (4.5:1) and also AAA (7:1) for normal text","why":"Correct. 7.27 is above both thresholds."},{"text":"It passes AA only because buttons count as large text","why":"Text size, not the element type, decides what counts as large. 14px regular is normal text."}],"answer":1},{"q":"<p>A long registration form is submitted with three errors. Where should focus go?</p>","options":[{"text":"To an error summary at the top listing the three problems as links to their fields","why":"Correct. Users hear how many problems there are and can jump to each one."},{"text":"Nowhere; the red borders show which fields are wrong","why":"Colour alone fails 1.4.1, and without a focus change screen reader users don’t know anything happened."},{"text":"To the submit button, so the user can try again","why":"Focus would stay where the user already is, and nothing would tell them what went wrong."}],"answer":0},{"q":"<p>A text-formatting toggle uses <code dir=\"ltr\">aria-pressed</code>, and its label also switches from “Bold” to “Unbold” when pressed. What is the problem?</p>","options":[{"text":"aria-pressed only works on checkboxes","why":"aria-pressed is the correct state for toggle buttons."},{"text":"Toggle buttons must use aria-expanded instead","why":"aria-expanded is for controls that show and hide other content."},{"text":"Changing both the label and the state gives a confusing announcement such as “Unbold, toggle button, pressed”; keep the label constant","why":"Correct. Either a fixed label with aria-pressed, or a changing label without it, but not both."}],"answer":2},{"q":"<p>A user deletes the last ticket in their basket, and the Remove button they pressed disappears. Where should focus go?</p>","options":[{"text":"Nowhere; the browser handles it","why":"The browser drops focus to the body, so the next Tab starts at the top of the page."},{"text":"To the site logo","why":"That takes the user out of the context they were working in."},{"text":"To the first link in the footer","why":"That is far from the basket and gives no feedback about what happened."},{"text":"To the basket heading or a “Your basket is empty” message made focusable with tabindex=“-1”","why":"Correct. The user stays in context and hears the result of their action."}],"answer":3},{"q":"<p>Two 20 × 20 px icon buttons have their centres 30 px apart. Do they meet 2.5.8 Target Size (Minimum)?</p>","options":[{"text":"No, every target must be at least 24 × 24 px","why":"There is a spacing exception for undersized targets."},{"text":"Yes, under the spacing exception: 24 px circles centred on each target don’t overlap each other or the other target","why":"Correct. With 30 px between centres, the 12 px radius circles stay clear. Bigger targets are still kinder."},{"text":"Yes, because icon buttons are exempt","why":"Icon buttons have no special exemption; only inline targets, equivalents, browser-controlled and essential ones do."}],"answer":1},{"q":"<p>An English article on Ticketly quotes a French review in a blockquote. What does WCAG require?</p>","options":[{"text":"<code dir=\"ltr\">lang=&quot;fr&quot;</code> on the blockquote, so screen readers switch to French pronunciation (3.1.2 Language of Parts)","why":"Correct. Passages in another language get their own lang attribute."},{"text":"<code dir=\"ltr\">dir=&quot;rtl&quot;</code> on the blockquote","why":"French is written left to right. dir is about direction, not language."},{"text":"Nothing, because the page already has lang=“en”","why":"The page language covers English content only. Other-language passages need their own lang."}],"answer":0},{"q":"<p>After each click on Add to basket, Ticketly uses <code dir=\"ltr\">role=&quot;alert&quot;</code> to say “Ticket added”. What is the problem?</p>","options":[{"text":"Alerts are never announced by screen readers","why":"Alerts are announced, and immediately, which is the issue."},{"text":"Live regions can’t contain the word “added”","why":"Any text can be announced from a live region."},{"text":"alert is assertive and interrupts speech; a routine confirmation should use role=“status”","why":"Correct. Save alert for rare, urgent messages, such as a failed payment."},{"text":"The message should be in the page title instead","why":"Changing the title isn’t announced reliably and misuses the title."}],"answer":2},{"q":"<p>Which testing method would reveal that a modal dialog leaves keyboard focus on the page behind it?</p>","options":[{"text":"An axe scan of the page with the dialog closed","why":"With the dialog closed there is nothing to test, and focus behaviour needs interaction anyway."},{"text":"Checking colour contrast with the DevTools picker","why":"Contrast has nothing to do with where focus goes."},{"text":"Validating the HTML","why":"The markup can be perfectly valid while the focus behaviour is broken."},{"text":"Opening the dialog with the keyboard and pressing Tab, or watching document.activeElement","why":"Correct. Focus management is about behaviour over time, which a person testing interactively sees immediately."}],"answer":3},{"q":"<p>What is wrong with this link?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> href</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"/artists/nour\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">img</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> src</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"nour.jpg\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> alt</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Nour Quartet\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> Nour Quartet&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n","options":[{"text":"The image needs role=“img”","why":"img elements already have the image role."},{"text":"The name becomes “Nour Quartet Nour Quartet”; the image should have alt=“” because the text already names the link","why":"Correct. When link text is present, an image inside that only repeats it should be marked decorative."},{"text":"Links can’t contain images","why":"Links can contain images; the alt text just has to fit the context."}],"answer":1},{"q":"<p>Which of these WCAG 2.2 criteria is Level AAA and so not required for an AA conformance claim?</p>","options":[{"text":"2.4.13 Focus Appearance","why":"Correct. It sets a minimum size and contrast for focus indicators at AAA. AA requires a visible indicator (2.4.7) that isn’t fully obscured (2.4.11)."},{"text":"2.5.8 Target Size (Minimum)","why":"This is AA and required: targets of at least 24 by 24 CSS pixels or adequately spaced."},{"text":"3.3.8 Accessible Authentication (Minimum)","why":"This is AA and required: no cognitive function test without an alternative or helper."},{"text":"2.4.11 Focus Not Obscured (Minimum)","why":"This is AA and required: focused elements can’t be entirely hidden by author content."}],"answer":0},{"q":"<p>Ticketly’s JavaScript auto-scrolls a carousel of artists. How should the code respect a reduced-motion preference?</p>","options":[{"text":"Check <code dir=\"ltr\">navigator.reducedMotion</code> before starting","why":"No such property exists. The preference is read through a media query."},{"text":"Ask the user with confirm() on every page load","why":"Users have already set the preference in their system. Asking again is an annoyance."},{"text":"Check <code dir=\"ltr\">window.matchMedia('(prefers-reduced-motion: reduce)').matches</code> and don’t start auto-scrolling when it is true, keeping a pause control either way","why":"Correct. Respect the system preference, and keep the pause control that 2.2.2 requires for everyone else."}],"answer":2}],"glossary":[{"id":"situational-disability","term":"Situational disability","definition":"A temporary limitation caused by circumstances rather than a person’s body, such as glare on a screen, a noisy room or holding a baby in one arm. Designs that serve permanent disabilities usually help here too.","lesson":"l-a11y-1-1"},{"id":"assistive-technology","term":"Assistive technology (AT)","definition":"Software or hardware people use to operate a computer in a way that suits them, such as screen readers, screen magnifiers, switch devices and voice control. It reads the page through the accessibility tree.","lesson":"l-a11y-1-2"},{"id":"accessibility-tree","term":"Accessibility tree","definition":"A simplified tree the browser builds from the DOM and CSS, where each node has a role, a name and any states or value. Assistive technologies read this tree, not the pixels on screen.","lesson":"l-a11y-1-2"},{"id":"screen-reader","term":"Screen reader","definition":"Assistive software that turns the accessibility tree into speech or braille and lets users navigate by headings, landmarks, links and form fields. Common ones are JAWS, NVDA, VoiceOver and TalkBack.","lesson":"l-a11y-1-2"},{"id":"visually-hidden","term":"Visually hidden text","definition":"Text clipped to a 1px box with CSS so it stays in the accessibility tree but takes no visible space. Unlike display: none, screen readers still announce it.","lesson":"l-a11y-1-2"},{"id":"wcag","term":"WCAG","definition":"The Web Content Accessibility Guidelines, the W3C standard for accessible web content. Version 2.2, published in October 2023, organises testable success criteria under four principles and three conformance levels.","lesson":"l-a11y-1-3"},{"id":"pour","term":"POUR","definition":"The four principles at the top of WCAG: content must be Perceivable, Operable, Understandable and Robust. Every guideline and success criterion sits under one of them.","lesson":"l-a11y-1-3"},{"id":"conformance-level","term":"Conformance level (A, AA, AAA)","definition":"The level at which a success criterion sits and at which conformance is claimed. Level AA, which includes all A criteria, is the target required by most laws and policies.","lesson":"l-a11y-1-3"},{"id":"european-accessibility-act","term":"European Accessibility Act (EAA)","definition":"EU Directive 2019/882, applying since 28 June 2025, which requires covered products and services such as e-commerce, banking and ticketing to be accessible. Its reference standard, EN 301 549, maps to WCAG 2.1 AA, with a WCAG 2.2 update published in 2026.","lesson":"l-a11y-1-3"},{"id":"landmark","term":"Landmark","definition":"A region of a page with a role that screen reader users can list and jump to, such as banner, navigation, main and contentinfo. HTML elements like header, nav, main and footer create them.","lesson":"l-a11y-2-1"},{"id":"autocomplete-token","term":"Autocomplete token","definition":"A value of the HTML autocomplete attribute, such as name, email or cc-number, that declares a field’s purpose so browsers can fill it in. It satisfies WCAG 1.3.5 Identify Input Purpose.","lesson":"l-a11y-2-3"},{"id":"alt-text","term":"Alt text","definition":"The text alternative of an image, given in its alt attribute. It should convey the image’s purpose in context: what it shows if informative, or what it does if it is a link or button.","lesson":"l-a11y-2-4"},{"id":"decorative-image","term":"Decorative image","definition":"An image that adds no information in its context, such as a divider or an ambient photo. It gets an empty alt attribute (alt=“”) so screen readers skip it instead of reading its file name.","lesson":"l-a11y-2-4"},{"id":"focus-order","term":"Focus order","definition":"The sequence in which Tab moves through focusable elements. It follows the DOM order, so markup should match the visual reading order, and positive tabindex values should never be used.","lesson":"l-a11y-3-1"},{"id":"focus-visible","term":":focus-visible","definition":"A CSS pseudo-class that matches when the browser decides focus should be shown, such as during keyboard navigation. Styling it with a strong outline gives keyboard users a clear indicator without showing rings on mouse clicks.","lesson":"l-a11y-3-1"},{"id":"skip-link","term":"Skip link","definition":"A link at the very start of a page, usually hidden until focused, that jumps to the main content. It lets keyboard users bypass repeated navigation, meeting WCAG 2.4.1 Bypass Blocks.","lesson":"l-a11y-3-1"},{"id":"modal-dialog","term":"Modal dialog","definition":"A window that blocks the rest of the page until closed. The native dialog element opened with showModal() moves focus inside, makes the page inert, closes on Escape and restores focus afterwards.","lesson":"l-a11y-3-2"},{"id":"inert","term":"inert","definition":"An HTML attribute that removes an element and its descendants from focus, pointer interaction and the accessibility tree. It suits closed drawers, off-screen panels and content behind a custom overlay.","lesson":"l-a11y-3-2"},{"id":"aria","term":"ARIA","definition":"Accessible Rich Internet Applications, a set of attributes for roles, states and properties that change what the accessibility tree exposes. It never adds behaviour, so native HTML is preferred whenever it exists.","lesson":"l-a11y-3-3"},{"id":"live-region","term":"Live region","definition":"An element whose content changes are announced by screen readers without moving focus. role=“status” is polite and role=“alert” is assertive; the region must exist before its text changes.","lesson":"l-a11y-3-3"},{"id":"apg","term":"ARIA Authoring Practices Guide (APG)","definition":"A W3C guide describing common widget patterns such as tabs, disclosure, dialog and menu button, with the roles, states and keyboard interaction users expect from each.","lesson":"l-a11y-3-4"},{"id":"roving-tabindex","term":"Roving tabindex","definition":"A technique for composite widgets where only the active item has tabindex=“0” and the rest have “-1”. The widget is one Tab stop, and arrow keys move focus and the 0 between items.","lesson":"l-a11y-3-4"},{"id":"contrast-ratio","term":"Contrast ratio","definition":"WCAG’s measure of the difference in relative luminance between two colours, from 1:1 to 21:1. Level AA needs 4.5:1 for normal text and 3:1 for large text and essential non-text elements.","lesson":"l-a11y-4-1"},{"id":"reflow","term":"Reflow","definition":"WCAG 1.4.10: content must fit a 320 CSS pixel wide viewport without horizontal scrolling, the width of a 1280px window at 400% zoom. Data tables and maps are exempt.","lesson":"l-a11y-4-2"},{"id":"prefers-reduced-motion","term":"prefers-reduced-motion","definition":"A CSS media feature that reflects the user’s operating system setting for less motion. Use it to replace large animations with fades or remove them for people with vestibular disorders.","lesson":"l-a11y-4-2"},{"id":"accessible-name","term":"Accessible name","definition":"The text that identifies an element to assistive technology. Browsers compute it from aria-labelledby, then aria-label, then native labelling such as label or alt, then content, then title.","lesson":"l-a11y-4-3"},{"id":"label-in-name","term":"Label in Name","definition":"WCAG 2.5.3: when a control has visible text, its accessible name must contain that text, ideally at the start, so voice control users can activate it by saying what they see.","lesson":"l-a11y-4-3"},{"id":"logical-properties","term":"Logical properties","definition":"CSS properties such as margin-inline-start and padding-inline-end that follow the writing direction instead of physical sides, so layouts mirror automatically for right-to-left languages like Arabic.","lesson":"l-a11y-4-4"},{"id":"axe-core","term":"axe-core","definition":"An open-source accessibility rules engine by Deque that runs in the page and reports violations with WCAG references. It powers axe DevTools, Lighthouse’s accessibility audit and test integrations such as @axe-core/playwright.","lesson":"l-a11y-5-1"},{"id":"browse-mode","term":"Browse mode","definition":"The NVDA mode in which a virtual cursor reads the page and single letters jump between elements, such as H for headings. Focus mode instead sends keys to the focused control for typing.","lesson":"l-a11y-5-2"}]}