← Accessible Components results

Accessible Components

GPT 5.6 terra · full

Initial view of Accessible Components

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 22,493 bytes · SHA-256 9bd8e3c22d6a
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Access Kit — Accessible Component Showcase</title>
<style>
:root{--ink:#1d2939;--muted:#667085;--line:#d9e2ec;--paper:#fff;--canvas:#f7f9fc;--navy:#173b6c;--blue:#1668d8;--mint:#0f8a72;--soft-blue:#eaf3ff;--soft-mint:#e8f7f2;--danger:#b42318;--r:14px;--s1:6px;--s2:10px;--s3:16px;--s4:24px;--s5:36px;--s6:56px;--fast:160ms;--normal:240ms;--shadow:0 12px 34px rgba(28,55,90,.10)}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--canvas);color:var(--ink);font:16px/1.55 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.skip{position:fixed;z-index:30;top:10px;left:10px;transform:translateY(-160%);background:var(--navy);color:#fff;padding:10px 15px;border-radius:8px;font-weight:700}.skip:focus{transform:translateY(0)}a{color:var(--navy)}button,input{font:inherit}button{cursor:pointer}.focusable:focus-visible,button:focus-visible,input:focus-visible,a:focus-visible,[role=tab]:focus-visible{outline:3px solid #f29b38;outline-offset:3px}.shell{display:grid;grid-template-columns:270px minmax(0,1fr);max-width:1460px;margin:auto;min-height:100vh}.side{position:sticky;top:0;height:100vh;padding:42px 28px;border-right:1px solid var(--line);background:#fbfcfe}.brand{display:flex;gap:10px;align-items:center;color:var(--navy);font-weight:800;letter-spacing:-.02em;font-size:19px;text-decoration:none}.mark{width:29px;height:29px;border-radius:8px;background:var(--navy);color:#fff;display:grid;place-items:center;font-size:14px}.side p{font-size:13px;color:var(--muted);margin:18px 0 28px}.side nav{display:grid;gap:5px}.side nav a{padding:9px 11px;border-radius:8px;text-decoration:none;color:#475467;font-size:14px;font-weight:650}.side nav a:hover,.side nav a:focus-visible{background:var(--soft-blue);color:var(--navy)}.side small{display:block;margin-top:35px;color:var(--muted);font-size:12px}main{padding:64px clamp(26px,6vw,92px) 90px;max-width:1120px}.eyebrow{margin:0 0 12px;color:var(--mint);font-weight:800;font-size:12px;letter-spacing:.12em;text-transform:uppercase}.hero{padding-bottom:46px;border-bottom:1px solid var(--line)}h1{font-size:clamp(38px,5vw,60px);line-height:1.06;letter-spacing:-.05em;max-width:720px;margin:0 0 18px;color:#102a4c}.lede{max-width:670px;font-size:18px;color:var(--muted);margin:0}.overview{display:flex;flex-wrap:wrap;gap:9px;margin-top:25px}.tag{font-size:13px;font-weight:700;color:#315477;background:var(--soft-blue);padding:5px 10px;border-radius:99px}.component{padding:60px 0;border-bottom:1px solid var(--line);scroll-margin-top:25px}.component-head{display:flex;align-items:baseline;gap:14px;margin-bottom:25px}.number{color:var(--mint);font-size:13px;font-weight:800;letter-spacing:.08em}.component h2{font-size:28px;letter-spacing:-.03em;margin:0;color:#102a4c}.demo{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);padding:clamp(22px,4vw,38px);box-shadow:0 2px 8px rgba(29,41,57,.025)}.caption{margin:20px 0 0;display:flex;align-items:center;gap:9px;color:var(--muted);font-size:14px}.key{font:600 12px ui-monospace,SFMono-Regular,Menlo,monospace;border:1px solid #c7d3e0;border-bottom-width:2px;background:#fff;border-radius:5px;padding:1px 5px;color:#344054}.btn{border:1px solid transparent;border-radius:8px;padding:10px 15px;font-weight:750;line-height:1.25;transition:background var(--fast),border var(--fast),transform var(--fast)}.btn-primary{background:var(--navy);color:white}.btn-primary:hover{background:#0d2d58}.btn-secondary{background:#fff;border-color:#b9c7d6;color:var(--navy)}.btn-secondary:hover{background:#f3f7fb}.action-note{min-height:25px;margin:18px 0 0;color:var(--mint);font-size:14px;font-weight:650}.menu-wrap{position:relative;display:inline-block}.menu{position:absolute;z-index:5;top:calc(100% + 8px);left:0;width:218px;margin:0;padding:7px;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);list-style:none}.menu [role=menuitem]{display:block;width:100%;text-align:left;border:0;border-radius:6px;background:transparent;color:var(--ink);padding:9px 11px;font-weight:620}.menu [role=menuitem]:hover,.menu [role=menuitem]:focus{background:var(--soft-blue);color:var(--navy);outline:none}.tabs{max-width:760px}.tablist{display:flex;gap:4px;border-bottom:1px solid var(--line)}[role=tab]{position:relative;border:0;background:transparent;padding:11px 14px;color:var(--muted);font-weight:750;border-radius:7px 7px 0 0}[role=tab][aria-selected=true]{color:var(--navy)}[role=tab][aria-selected=true]::after{content:"";position:absolute;left:10px;right:10px;bottom:-1px;height:3px;border-radius:3px 3px 0 0;background:var(--blue)}[role=tabpanel]{padding:22px 4px 3px}.panel-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.mini-card{border:1px solid var(--line);border-radius:9px;padding:15px}.mini-card strong{display:block;color:var(--navy)}.mini-card p{margin:4px 0 0;color:var(--muted);font-size:14px}.combo-wrap{position:relative;max-width:500px}.combo-label{display:block;margin-bottom:7px;font-size:14px;font-weight:750;color:#344054}.combo-input{width:100%;border:1px solid #9aaabd;border-radius:8px;padding:11px 42px 11px 12px;color:var(--ink);background:white}.combo-wrap::after{content:"⌄";position:absolute;right:14px;top:39px;color:var(--navy);font-size:19px;pointer-events:none}.listbox{position:absolute;z-index:5;top:calc(100% + 6px);left:0;right:0;max-height:220px;overflow-y:auto;background:#fff;border:1px solid var(--line);border-radius:9px;padding:5px;box-shadow:var(--shadow)}[role=option]{padding:8px 10px;border-radius:6px;cursor:default}[role=option][aria-selected=true]{background:var(--soft-blue);color:var(--navy);font-weight:750}.field-help{margin:10px 0 0;font-size:13px;color:var(--muted)}.accordion{max-width:760px;border-top:1px solid var(--line)}.acc-item{border-bottom:1px solid var(--line)}.acc-button{width:100%;display:flex;justify-content:space-between;align-items:center;text-align:left;border:0;background:transparent;padding:17px 4px;color:var(--navy);font-weight:780}.chevron{font-size:20px;color:var(--mint);transition:transform var(--normal)}.acc-button[aria-expanded=true] .chevron{transform:rotate(45deg)}.acc-panel{overflow:hidden;transition:height var(--normal) ease}.acc-panel[hidden]{display:none}.acc-inner{padding:0 4px 19px;color:var(--muted)}.backdrop{position:fixed;z-index:20;inset:0;background:rgba(14,29,52,.52);display:grid;place-items:center;padding:24px}.dialog{width:min(520px,100%);background:#fff;border-radius:15px;border:1px solid #cbd5e1;padding:27px;box-shadow:0 24px 70px rgba(2,19,43,.36)}.dialog h2{margin:0;color:#102a4c;font-size:25px;letter-spacing:-.025em}.dialog p{color:var(--muted);margin:9px 0 24px}.dialog-actions{display:flex;justify-content:flex-end;gap:10px}.status{position:fixed;left:12px;bottom:12px;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
@media(max-width:780px){.shell{display:block}.side{position:static;height:auto;padding:18px 22px;border-right:0;border-bottom:1px solid var(--line)}.side p,.side small{display:none}.side nav{grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.side nav a{padding:6px 8px;font-size:12px}main{padding:42px 22px 60px}.component{padding:45px 0}.panel-grid{grid-template-columns:1fr}.dialog-actions{flex-wrap:wrap}}
@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;animation-duration:1ms!important;transition-duration:1ms!important}}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to main content</a>
<div class="shell" id="page-shell">
<aside class="side" aria-label="Component navigation"><a class="brand" href="#main"><span class="mark">A</span> Access Kit</a><p>Interaction patterns built to be used — by everyone.</p><nav><a href="#modal">01 Modal dialog</a><a href="#menu">02 Dropdown menu</a><a href="#tabs">03 Tabs</a><a href="#combobox">04 Combobox</a><a href="#accordion">05 Disclosure group</a></nav><small>Vanilla JavaScript<br>WAI-ARIA patterns</small></aside>
<main id="main" tabindex="-1">
<header class="hero"><p class="eyebrow">Interaction foundations</p><h1>Components with the keyboard built in.</h1><p class="lede">A small, practical showcase of inclusive interface patterns. Every control here has a predictable focus path, visible state, and a clear spoken name.</p><div class="overview"><span class="tag">Keyboard first</span><span class="tag">Screen-reader ready</span><span class="tag">Reduced-motion aware</span></div></header>
<section class="component" id="modal" aria-labelledby="modal-title"><div class="component-head"><span class="number">01 / 05</span><h2 id="modal-title">Modal dialog</h2></div><div class="demo"><button class="btn btn-primary" id="open-modal">Open confirmation dialog</button><p class="action-note" id="modal-note" aria-live="polite"></p></div><p class="caption"><span class="key">Tab</span> trapped in dialog · <span class="key">Esc</span> close · focus returns to trigger</p></section>
<section class="component" id="menu" aria-labelledby="menu-title"><div class="component-head"><span class="number">02 / 05</span><h2 id="menu-title">Dropdown menu</h2></div><div class="demo"><div class="menu-wrap"><button class="btn btn-secondary" id="menu-button" aria-haspopup="menu" aria-expanded="false" aria-controls="action-menu">Project actions <span aria-hidden="true">⌄</span></button><ul class="menu" id="action-menu" role="menu" aria-label="Project actions" hidden><li role="none"><button role="menuitem">Duplicate project</button></li><li role="none"><button role="menuitem">Move to archive</button></li><li role="none"><button role="menuitem">Export summary</button></li></ul></div><p class="action-note" id="menu-note" aria-live="polite"></p></div><p class="caption"><span class="key">↑↓</span> navigate · <span class="key">Home End</span> jump · <span class="key">Enter</span> select · <span class="key">Esc</span> close</p></section>
<section class="component" id="tabs" aria-labelledby="tabs-title"><div class="component-head"><span class="number">03 / 05</span><h2 id="tabs-title">Tabs</h2></div><div class="demo"><div class="tabs"><div class="tablist" role="tablist" aria-label="Workspace information"><button role="tab" id="tab-overview" aria-selected="true" aria-controls="panel-overview" tabindex="0">Overview</button><button role="tab" id="tab-activity" aria-selected="false" aria-controls="panel-activity" tabindex="-1">Activity</button><button role="tab" id="tab-members" aria-selected="false" aria-controls="panel-members" tabindex="-1">Members</button></div><div id="panel-overview" role="tabpanel" aria-labelledby="tab-overview" tabindex="0"><div class="panel-grid"><div class="mini-card"><strong>14 active tasks</strong><p>Three are due this week.</p></div><div class="mini-card"><strong>84% complete</strong><p>Progress is ahead of plan.</p></div></div></div><div id="panel-activity" role="tabpanel" aria-labelledby="tab-activity" tabindex="0" hidden><strong>Latest activity</strong><p>Rae updated the launch checklist 12 minutes ago.</p><a href="#tabs">Review activity log</a></div><div id="panel-members" role="tabpanel" aria-labelledby="tab-members" tabindex="0" hidden><strong>Team members</strong><p>Six contributors have access to this workspace.</p><button class="btn btn-secondary" type="button">Manage access</button></div></div></div><p class="caption"><span class="key">← →</span> switch tabs · one tab stop · <span class="key">Tab</span> enters active panel</p></section>
<section class="component" id="combobox" aria-labelledby="combo-title"><div class="component-head"><span class="number">04 / 05</span><h2 id="combo-title">Combobox autocomplete</h2></div><div class="demo"><div class="combo-wrap"><label class="combo-label" for="city-input">Choose a city</label><input class="combo-input" id="city-input" role="combobox" type="text" autocomplete="off" aria-autocomplete="list" aria-expanded="false" aria-controls="city-list" aria-activedescendant="" aria-describedby="city-help" placeholder="Start typing a city"><div class="listbox" id="city-list" role="listbox" aria-label="City suggestions" hidden></div></div><p class="field-help" id="city-help">Twenty destinations available. Type to filter results.</p><p class="action-note" id="city-note" aria-live="polite"></p></div><p class="caption"><span class="key">↑↓</span> highlight · <span class="key">Enter</span> choose · <span class="key">Esc</span> revert and close</p></section>
<section class="component" id="accordion" aria-labelledby="accordion-title"><div class="component-head"><span class="number">05 / 05</span><h2 id="accordion-title">Disclosure group</h2></div><div class="demo"><div class="accordion"><div class="acc-item"><h3><button class="acc-button" id="acc-one" aria-expanded="false" aria-controls="region-one">What makes this pattern accessible?<span class="chevron" aria-hidden="true">+</span></button></h3><div class="acc-panel" id="region-one" role="region" aria-labelledby="acc-one" hidden><div class="acc-inner">The native button handles Enter and Space. Its expanded state stays synchronized with the region, which is hidden from all users only after the closing transition completes.</div></div></div><div class="acc-item"><h3><button class="acc-button" id="acc-two" aria-expanded="false" aria-controls="region-two">Can more than one section stay open?<span class="chevron" aria-hidden="true">+</span></button></h3><div class="acc-panel" id="region-two" role="region" aria-labelledby="acc-two" hidden><div class="acc-inner">Yes. This is a disclosure group rather than an exclusive accordion: each section works independently, so readers can compare details without losing their place.</div></div></div><div class="acc-item"><h3><button class="acc-button" id="acc-three" aria-expanded="false" aria-controls="region-three">How is motion handled?<span class="chevron" aria-hidden="true">+</span></button></h3><div class="acc-panel" id="region-three" role="region" aria-labelledby="acc-three" hidden><div class="acc-inner">Height changes use a brief transition, while the reduced-motion preference eliminates movement. Content is never hidden from assistive technology while it is visibly open.</div></div></div></div></div><p class="caption"><span class="key">Enter Space</span> toggle · independent sections · regions are labeled</p></section>
</main></div>
<div class="backdrop" id="modal-backdrop" hidden><div class="dialog" id="confirm-dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-description" tabindex="-1"><h2 id="dialog-title">Confirm your changes</h2><p id="dialog-description">Your workspace preferences will be updated for everyone on the project.</p><div class="dialog-actions"><button class="btn btn-secondary" id="cancel-modal">Cancel</button><button class="btn btn-primary" id="confirm-modal">Confirm changes</button></div></div></div>
<div class="status" id="sr-status" role="status" aria-live="polite"></div>
<script>
'use strict';
// Tunable interaction constants
const CONFIG={animationMs:240, cities:['Amsterdam','Athens','Auckland','Barcelona','Berlin','Boston','Cairo','Cape Town','Chicago','Copenhagen','Dublin','Helsinki','Lisbon','London','Melbourne','Montreal','New York','Osaka','Paris','Singapore']};
const $=(s,r=document)=>r.querySelector(s); const $$=(s,r=document)=>[...r.querySelectorAll(s)];
const announce=text=>{$('#sr-status').textContent=''; requestAnimationFrame(()=>$('#sr-status').textContent=text)};
const focusables=root=>$$('button:not([disabled]),[href],input:not([disabled]),[tabindex]:not([tabindex="-1"])',root).filter(e=>!e.hidden&&e.offsetParent!==null);
// Shared focus-trap utility
function trapFocus(event,container){if(event.key!=='Tab')return;const items=focusables(container);if(!items.length){event.preventDefault();return}event.preventDefault();const index=items.indexOf(document.activeElement);const next=(index+(event.shiftKey?-1:1)+items.length)%items.length;items[next].focus()}
// Modal dialog
const modalBackdrop=$('#modal-backdrop'),dialog=$('#confirm-dialog'),modalTrigger=$('#open-modal');
function openModal(){modalBackdrop.hidden=false;$('#page-shell').inert=true;document.body.style.overflow='hidden';$('#confirm-modal').focus()}
function closeModal(message=''){modalBackdrop.hidden=true;$('#page-shell').inert=false;document.body.style.overflow='';modalTrigger.focus();if(message){$('#modal-note').textContent=message;announce(message)}}
modalTrigger.addEventListener('click',openModal); dialog.addEventListener('keydown',e=>{trapFocus(e,dialog);if(e.key==='Escape'){e.preventDefault();closeModal('Dialog closed.')}}); modalBackdrop.addEventListener('mousedown',e=>{if(e.target===modalBackdrop)closeModal('Dialog closed.')});$('#cancel-modal').onclick=()=>closeModal('Changes cancelled.');$('#confirm-modal').onclick=()=>closeModal('Changes confirmed.');
// Dropdown menu
const menuButton=$('#menu-button'),menu=$('#action-menu'),menuItems=$$('[role=menuitem]',menu);
function setMenu(open,focusIndex=null){menu.hidden=!open;menuButton.setAttribute('aria-expanded',String(open));if(open&&focusIndex!==null)menuItems[focusIndex].focus()}
function menuMove(current,delta){const i=menuItems.indexOf(current);menuItems[(i+delta+menuItems.length)%menuItems.length].focus()}
menuButton.addEventListener('click',()=>setMenu(menu.hidden));menuButton.addEventListener('keydown',e=>{if(['ArrowDown','Enter',' '].includes(e.key)){e.preventDefault();setMenu(true,e.key==='ArrowDown'?0:null)}else if(e.key==='ArrowUp'){e.preventDefault();setMenu(true,menuItems.length-1)}});
menu.addEventListener('keydown',e=>{const item=document.activeElement;if(e.key==='ArrowDown'){e.preventDefault();menuMove(item,1)}if(e.key==='ArrowUp'){e.preventDefault();menuMove(item,-1)}if(e.key==='Home'){e.preventDefault();menuItems[0].focus()}if(e.key==='End'){e.preventDefault();menuItems.at(-1).focus()}if(e.key==='Escape'){e.preventDefault();setMenu(false);menuButton.focus()}if(e.key==='Tab')setMenu(false)});
menuItems.forEach(item=>item.addEventListener('click',()=>{const msg=item.textContent+' selected.';setMenu(false);menuButton.focus();$('#menu-note').textContent=msg;announce(msg)}));document.addEventListener('mousedown',e=>{if(!menu.hidden&&!e.target.closest('.menu-wrap'))setMenu(false)});
// Tabs: automatic activation, roving tab stop
const tabs=$$('[role=tab]'),panels=$$('[role=tabpanel]');
function activateTab(tab,focus=false){tabs.forEach(t=>{const active=t===tab;t.setAttribute('aria-selected',String(active));t.tabIndex=active?0:-1;$('#'+t.getAttribute('aria-controls')).hidden=!active});if(focus)tab.focus()}
tabs.forEach((tab,i)=>tab.addEventListener('keydown',e=>{let next=null;if(e.key==='ArrowRight')next=tabs[(i+1)%tabs.length];if(e.key==='ArrowLeft')next=tabs[(i-1+tabs.length)%tabs.length];if(e.key==='Home')next=tabs[0];if(e.key==='End')next=tabs.at(-1);if(next){e.preventDefault();activateTab(next,true)}}));tabs.forEach(t=>t.addEventListener('click',()=>activateTab(t)));
// Combobox: aria-activedescendant manager
const input=$('#city-input'),listbox=$('#city-list');let filtered=[],active=-1,committed='';
function renderOptions(){const query=input.value.trim().toLowerCase();filtered=CONFIG.cities.filter(c=>c.toLowerCase().includes(query));active=filtered.length?0:-1;listbox.innerHTML=filtered.length?filtered.map((city,i)=>`<div id="city-option-${CONFIG.cities.indexOf(city)}" role="option" aria-selected="${i===active}">${city}</div>`).join(''):'<div role="option" aria-disabled="true">No matching cities</div>';listbox.hidden=false;input.setAttribute('aria-expanded','true');syncActive()}
function syncActive(){const options=$$('[role=option]',listbox);options.forEach((o,i)=>o.setAttribute('aria-selected',String(i===active)));const opt=options[active];input.setAttribute('aria-activedescendant',opt&&opt.id||'');if(opt)opt.scrollIntoView({block:'nearest'})}
function closeCombo(revert=false){if(revert)input.value=committed;listbox.hidden=true;input.setAttribute('aria-expanded','false');input.setAttribute('aria-activedescendant','')}
function choose(){if(active<0||!filtered[active])return;committed=filtered[active];input.value=committed;closeCombo();const msg=committed+' selected.';$('#city-note').textContent=msg;announce(msg)}
input.addEventListener('input',renderOptions);input.addEventListener('focus',()=>renderOptions());input.addEventListener('keydown',e=>{if(e.key==='ArrowDown'){e.preventDefault();if(listbox.hidden)renderOptions();else if(filtered.length){active=(active+1)%filtered.length;syncActive()}}else if(e.key==='ArrowUp'){e.preventDefault();if(listbox.hidden)renderOptions();else if(filtered.length){active=(active-1+filtered.length)%filtered.length;syncActive()}}else if(e.key==='Enter'&&!listbox.hidden){e.preventDefault();choose()}else if(e.key==='Escape'&&!listbox.hidden){e.preventDefault();closeCombo(true)}});input.addEventListener('blur',()=>setTimeout(()=>{if(!listbox.contains(document.activeElement))closeCombo()},120));listbox.addEventListener('mousedown',e=>{const option=e.target.closest('[role=option]');if(option&&!option.hasAttribute('aria-disabled')){active=$$('[role=option]',listbox).indexOf(option);choose();input.focus()}e.preventDefault()});
// Accordion with height animation and delayed hidden state
$$('.acc-button').forEach(button=>button.addEventListener('click',()=>{const panel=$('#'+button.getAttribute('aria-controls')),opening=button.getAttribute('aria-expanded')==='false';button.setAttribute('aria-expanded',String(opening));if(opening){panel.hidden=false;panel.style.height='0px';requestAnimationFrame(()=>panel.style.height=panel.scrollHeight+'px');panel.addEventListener('transitionend',function done(){panel.style.height='auto';panel.removeEventListener('transitionend',done)})}else{panel.style.height=panel.scrollHeight+'px';requestAnimationFrame(()=>panel.style.height='0px');panel.addEventListener('transitionend',function done(){panel.hidden=true;panel.style.height='';panel.removeEventListener('transitionend',done)})}}));
</script>
</body></html>
<!-- agent-meta {"model":"openai/gpt-5.6-terra","provider":"openrouter","persona":"full","sessionId":"09252752-6329-44d4-90d6-463640b40fd5","tokensIn":271053,"tokensOut":11291,"tokensTotal":282344,"turns":21,"toolCalls":26,"failedToolCalls":1,"timestamp":"2026-07-31T19:30:14.063Z"} -->