Tools
▾
🎨 Color Picker
🌈 Gradient Generator
🌑 Box Shadow
📐 Flexbox Playground
🔲 CSS Grid Builder
🔷 SVG Shapes
📋 JSON Formatter
🔍 Regex Tester
All tools →
Learn
▾
HTML
CSS
JavaScript
TypeScript
PHP
React
Laravel
SQL
Git
All learning paths →
Roadmaps
▾
🖥️ Frontend Developer
🐘 PHP Developer
⚡ JavaScript
🌐 Full-Stack
All roadmaps →
Projects
Blog
Code Editor
Sign in
Get Started Free
GizDevCraft Editor - ARIA Roles & Attributes
▶ Run
🔗 Share
HTML
CSS
JS
<a class="skip-link" href="#lessonMain">Skip to practice area</a> <main id="lessonMain" class="lesson-shell a11y-playground"> <section class="demo-card" aria-labelledby="a11yTitle"> <span class="eyebrow">ARIA Roles & Attributes</span> <h1 id="a11yTitle">Accessibility practice area</h1> <p>Use Tab, Shift+Tab, Enter, Space, and Escape while you edit labels, focus, errors, contrast, ARIA states, and reduced motion.</p> <nav class="a11y-nav" aria-label="Accessibility practice sections"> <a href="#a11yForm">Form</a> <a href="#a11yDialogSection">Dialog</a> <a href="#a11yImageSection">Images</a> </nav> <form id="a11yForm" class="a11y-panel" novalidate> <h2>Accessible signup form</h2> <div id="errorSummary" class="error-summary" role="alert" tabindex="-1" hidden></div> <label for="studentName">Name</label> <input id="studentName" name="studentName" autocomplete="name" aria-describedby="nameHint"> <p id="nameHint" class="hint">Enter the name shown on your certificate.</p> <label for="studentEmail">Email</label> <input id="studentEmail" name="studentEmail" type="email" autocomplete="email" aria-describedby="emailHint emailError"> <p id="emailHint" class="hint">Use an email address you check often.</p> <p id="emailError" class="field-error" hidden>Enter an email address with an @ symbol.</p> <fieldset> <legend>Preferred lesson format</legend> <label><input type="radio" name="format" value="text" checked> Text lesson</label> <label><input type="radio" name="format" value="video"> Video with captions</label> </fieldset> <button class="action" type="submit">Check form</button> <p id="formStatus" role="status"></p> </form> <section id="a11yDialogSection" class="a11y-panel" aria-labelledby="dialogSectionTitle"> <h2 id="dialogSectionTitle">Focus and ARIA state</h2> <button id="menuButton" class="action" type="button" aria-expanded="false" aria-controls="practiceMenu">Toggle menu</button> <ul id="practiceMenu" class="practice-menu" hidden> <li><a href="#a11yForm">Review form labels</a></li> <li><a href="#a11yImageSection">Review image text</a></li> </ul> <button id="openDialog" class="action" type="button">Open focus dialog</button> <dialog id="lessonDialog" aria-labelledby="dialogTitle"> <h3 id="dialogTitle">Focus practice</h3> <p>Focus moves here when the dialog opens and returns to the opener when it closes.</p> <button id="closeDialog" type="button">Close dialog</button> </dialog> </section> <section id="a11yImageSection" class="a11y-panel" aria-labelledby="imageSectionTitle"> <h2 id="imageSectionTitle">Images and motion</h2> <figure> <div class="image-demo" role="img" aria-label="Dashboard card showing readable labels and clear focus states">Image preview</div> <figcaption>Informative images need useful text alternatives.</figcaption> </figure> <div class="motion-card">Motion should be calm when reduced motion is requested.</div> </section> <details class="code-reference"> <summary>Lesson code reference</summary> <pre class="code-sample"><code><button aria-expanded="false" aria-controls="menu"> Menu </button> <nav id="menu" hidden aria-label="Primary"> <a href="/learn">Learn</a> </nav> <div role="status" aria-live="polite">Saved</div></code></pre> </details> </section> </main>
body { margin: 0; min-height: 100vh; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #f8fafc; color: #111827; } .lesson-shell { min-height: 100vh; display: grid; place-items: center; padding: 2rem; } .demo-card { width: min(760px, 100%); background: #ffffff; border: 1px solid #dbe3ef; border-radius: 12px; padding: 2rem; box-shadow: 0 18px 45px rgb(15 23 42 / .10); text-align: center; } .eyebrow { display: inline-block; margin-bottom: .75rem; color: #4f46e5; font-weight: 800; font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; } h1 { margin: 0 0 .75rem; font-size: clamp(1.8rem, 4vw, 3rem); } p { color: #536471; line-height: 1.7; } button { border: 0; border-radius: 8px; padding: .75rem 1rem; background: #4f46e5; color: white; font-weight: 800; cursor: pointer; } .demo-target { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; margin-top: 1.5rem; } .box { border: 1px solid #dbe3ef; border-radius: 8px; padding: 1.25rem; background: #f8fafc; font-weight: 800; } .featured { background: #eef2ff; color: #3730a3; } .skip-link { position: fixed; inset-block-start: .75rem; inset-inline-start: .75rem; z-index: 10; transform: translateY(-160%); background: #111827; color: #ffffff; padding: .75rem 1rem; border-radius: 8px; } .skip-link:focus { transform: translateY(0); } .a11y-playground .demo-card { max-width: 980px; text-align: left; } .a11y-nav { display: flex; flex-wrap: wrap; gap: .75rem; margin-block: 1rem; } .a11y-panel { display: grid; gap: .75rem; border: 1px solid #d7dde8; border-radius: 8px; padding: 1rem; margin-block: 1rem; background: #ffffff; } .a11y-panel label { font-weight: 700; } .a11y-panel input { min-height: 2.5rem; border: 1px solid #64748b; border-radius: 8px; padding: .55rem .7rem; font: inherit; } fieldset { display: grid; gap: .55rem; border: 1px solid #cbd5e1; border-radius: 8px; padding: 1rem; } .action, .a11y-nav a, dialog button { border: 0; border-radius: 8px; background: #1d4ed8; color: #ffffff; padding: .7rem 1rem; font-weight: 800; text-decoration: none; width: fit-content; } .action:focus-visible, .a11y-nav a:focus-visible, input:focus-visible, summary:focus-visible, dialog button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 3px; } .hint { color: #475569; margin: 0; } .field-error, .error-summary { color: #7f1d1d; background: #fee2e2; border: 1px solid #991b1b; border-radius: 8px; padding: .75rem; } .practice-menu { display: grid; gap: .5rem; padding: 1rem 1.25rem; background: #f8fafc; border-radius: 8px; } dialog { max-width: 28rem; border: 1px solid #334155; border-radius: 8px; padding: 1.25rem; } dialog::backdrop { background: rgb(15 23 42 / .55); } .image-demo { display: grid; place-items: center; min-height: 8rem; border-radius: 8px; background: #dbeafe; color: #1e3a8a; font-weight: 800; } .motion-card { border-radius: 8px; background: #ecfdf5; color: #14532d; padding: 1rem; transition: transform .25s ease, background-color .25s ease; } .motion-card:hover { transform: translateY(-4px); background: #bbf7d0; } .code-sample { text-align: left; background: #111827; color: #e5e7eb; padding: 1rem; border-radius: 8px; overflow: auto; white-space: pre-wrap; } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; } .motion-card:hover { transform: none; } }
const lessonTitle = "ARIA Roles & Attributes"; const form = document.querySelector('#a11yForm'); const email = document.querySelector('#studentEmail'); const emailError = document.querySelector('#emailError'); const errorSummary = document.querySelector('#errorSummary'); const formStatus = document.querySelector('#formStatus'); const menuButton = document.querySelector('#menuButton'); const menu = document.querySelector('#practiceMenu'); const dialog = document.querySelector('#lessonDialog'); const openDialog = document.querySelector('#openDialog'); const closeDialog = document.querySelector('#closeDialog'); form?.addEventListener('submit', event => { event.preventDefault(); const validEmail = email.value.includes('@'); email.setAttribute('aria-invalid', String(!validEmail)); emailError.hidden = validEmail; errorSummary.hidden = validEmail; if (!validEmail) { errorSummary.textContent = 'Fix 1 error before continuing: enter a valid email address.'; formStatus.textContent = ''; errorSummary.focus(); return; } errorSummary.textContent = ''; formStatus.textContent = 'Accessibility check passed for ' + lessonTitle + '.'; }); menuButton?.addEventListener('click', () => { const open = menuButton.getAttribute('aria-expanded') === 'true'; menuButton.setAttribute('aria-expanded', String(!open)); menu.hidden = open; }); openDialog?.addEventListener('click', () => { dialog.showModal(); closeDialog.focus(); }); closeDialog?.addEventListener('click', () => dialog.close()); dialog?.addEventListener('close', () => openDialog.focus());
Our Network
GizDevCraft
40+ Free Developer Tools
GizBotArena
Device Platforms
GizCalc
750+ Free Calculators