Semantic Html
Published by honoluluhenk in agent-skills
What this skill does
>-
Add Semantic Html to your agent
Review the source and files first. When you are ready, copy the prompt instruction or use the CLI command supported by your environment.
Install with a prompt
Paste this into a compatible coding agent:
add this skill "semantic-html" from https://github.com/honoluluhenk/agent-skillsInstall with the CLI
Run this command in a controlled environment after reviewing the repository:
npx skills add https://github.com/honoluluhenk/agent-skills --skill semantic-htmlSkill instructions
Semantic HTML
Write HTML that is semantic, accessible, and structurally honest. Every element must earn its place on meaning and accessibility grounds, not appearance. The leading word is accessible structure: the bare meaningful skeleton of a page, where each element justifies itself by what it communicates to the accessibility tree.
When to Use This Skill
- writing, reviewing, or refactoring any HTML markup
- choosing between semantic elements and
div/spanfallbacks (full element list in rule A.1) - auditing or fixing heading hierarchy and landmark structure
- applying or reviewing ARIA roles, states, and properties
- reviewing form labels, input types, field grouping, or error associations
- checking keyboard accessibility, focus order, and skip links
- writing alt text, icon/SVG names, table captions, or accessible names
- debugging screen-reader or accessibility-tree output
Do not use this skill for:
- CSS layout, styling, or visual design decisions (including colour contrast, reflow, and reduced motion)
- JavaScript behaviour unless the HTML or ARIA choice is the root issue
- template or component-framework syntax (Svelte, JSX, etc.) unless the HTML semantics within them are the subject
- content strategy, copywriting, or plain-text concerns
How to Use This Skill
- Read the markup in source order. Map the landmarks, the heading outline, and the focus order before judging anything.
- Walk the rules section by section (A–I below). For each violation, record where it is, which rule it breaks, and a concrete fix.
- Verify what you claim. Confirm accessible-name, ARIA, and keyboard claims against the accessibility tree or a keyboard-only walkthrough where you can — do not assert conformance you have not checked.
- Present the results using the template under Present Results to User.
When writing new markup rather than reviewing, work in the same order: build the semantic skeleton and a logical source order first, give every interactive control an accessible name, and leave presentation to CSS.
Completion criterion: every rule in sections A–I has been checked against the markup, and each finding names the offending element plus a concrete fix. If any part is unverifiable, say so rather than assuming it passes.
Rules
Each rule is the single source of truth for its topic; the offending markup and its correction live beside it. For
worked before/after snippets per section, read references/examples.md. For the exact WCAG 2.2 criteria, the
target-size exceptions, the accessible-name algorithm, and ARIA attribute details, read references/wcag-and-aria.md
when a finding needs to cite a criterion or handle an edge case.
A. Core Principles
-
Prefer semantic elements. Use the HTML element whose meaning matches the content (
section,article,aside,nav,main,header,footer,form,button,a,p,h1–h6,ul,ol,li,dl,dt,dd,figure,figcaption,details,summary,dialog,table,th,td,caption,img,blockquote,hr,address,pre,code,em,strong,abbr,time,mark,cite,dfn,progress,meter). Reach fordiv/spanonly when no semantic element fits. -
Avoid semantic overfitting. Do not force a semantic element where a plain container is more accurate. A
divis fine when no stronger semantic exists. Accuracy over mechanical compliance. -
Content and behaviour separate. HTML defines structure, CSS defines presentation, JavaScript defines behaviour. No inline
onclick=""strings or inline styles; build the semantic structure before any layout. -
Keep nesting shallow. No unnecessary wrappers. Every extra layer must justify itself on structural, semantic, or accessibility grounds.
B. Document Structure
-
Source order must be logical. The reading and navigation order must make sense without CSS. Place content in DOM order so that screen-reader users encounter it in a meaningful sequence, before any visual reordering.
-
Landmarks must be meaningful. Use
main,nav,header,footer,asidewhere they help orientation. When multiple landmarks of the same type appear on a page, distinguish them witharia-labeloraria-labelledby. Do not wrap every subsection in a landmark. -
Headings form a logical hierarchy. One
h1per page or main view. Follow a clear order (h1→h2→h3); do not skip levels without reason, and never pick a heading level for its visual size. Every sectioning element (section,article,nav,aside) should contain a heading that describes its content. -
Declare the language and direction. Set
langon<html>and on any content that switches language, so screen readers pronounce text correctly. Setdirwhen the base direction is right-to-left.
C. Content Semantics
-
Use lists only for actual lists.
ul/olfor list semantics (steps, menu items, grouped items where list membership is the meaning). Do not wrap merely decorative or repeating content inul/liwhen list membership carries no meaning. -
Use
articlefor standalone entries. Usearticlewhen each repeated item can stand on its own — cards, posts, results, stories — with its own heading, metadata, or actions. For a genuine list of such entries, nest them asli > article. -
Use native disclosure and status widgets. Prefer
<details>/<summary>for collapsible sections,<dialog>for modals,<progress>for task completion,<meter>for scalar measurements. These expose state automatically to the accessibility tree.
D. Images & Icons
-
Images need intentional
alt.alt=""for decorative images. Descriptive, concisealttext for informative images conveying information a sighted user would see and that matters in context. Usefigure/figcaptionwhen the caption is part of the content. Never render text as an image. -
Icons and inline SVG carry a name or are hidden. An inline
<svg>that conveys meaning needsrole="img"plus a<title>(oraria-label); a decorative icon or SVG getsaria-hidden="true". An icon-only button needs an accessible name viaaria-labelor visually-hidden text — the glyph alone names nothing.
E. Tables
- Data tables must be accessible. Use
<th>withscope="col"/scope="row", and provide a<caption>for the table's accessible name. For tables with multiple header levels or an irregular layout, associate each cell with its headers viaheaders/id. Never use tables for layout.
F. Links
-
Link text must be meaningful out of context. No "click here", "read more", or "learn more" without disambiguation. The link text alone should convey its destination or purpose.
-
External and file links need indicators. Announce when a link opens a new tab or downloads a file, either in the link text or via an icon with appropriate alt text.
-
Skip links. Provide a skip-to-main-content link as the first focusable element on the page, linking to
#mainor equivalent.
G. Interactive Elements & Forms
-
Use correct interactive elements.
<button>for actions,<a href="...">for navigation. Never use a clickabledivorspan, or a bare<a>with a click handler but nohref— neither is focusable or operable by keyboard. Give every<button>in a form an explicittype(submit,button, orreset); the default issubmit. If a non-interactive element must play an interactive role, addrole,tabindex, and keyboard event handling. -
Forms must be explicit. Every input needs an associated
<label>. Usefieldset/legendfor grouped controls (radio groups, address blocks). Mark required fields with therequiredattribute, not only text. Do not rely onplaceholderas a label. -
Inputs declare their purpose. Choose the input
typethat matches the data (email,tel,url,number,date) so browsers validate and mobile keyboards adapt, and add the rightautocompletetoken (name,email,username,current-password,new-password) so browsers and password managers can fill (WCAG 2.2 AA: Identify Input Purpose). -
Error messages associate with input. Link error text to the input via
aria-describedby, and mark the fieldaria-invalid. Errors must be perceivable and programmatically associated. -
Authentication must not require cognitive-function tests. Provide at least one authentication path that does not rely on a cognitive-function test — remembering a site-specific password, transcribing a code, or solving a puzzle (WCAG 2.2 AA: Accessible Authentication, Minimum). If a cognitive test is used, offer an alternative method, and never block paste or password-manager fill. Object-recognition tests are permitted at AA level; the strict "no cognitive tests at all" rule is AAA.
H. Focus & Keyboard
-
Focus must not be obscured. Keyboard focus indicators must not be hidden by sticky headers, footers, overlays, or other elements (WCAG 2.2 AA: Focus Not Obscured).
-
No keyboard traps. All focusable elements must be navigable away from using standard keyboard keys (Tab, Shift+Tab, Escape).
-
Touch targets meet the size or spacing rule. Interactive elements must be at least 24×24 CSS pixels, or be spaced so that a 24 px diameter circle centered on each target does not intersect a neighbor (WCAG 2.2 AA: Target Size, Minimum). Exceptions apply to inline links in a sentence, user-agent-controlled sizes, and essential targets — see the reference file for the full list.
-
tabindexstays minimal. Use0for natively focusable elements and-1for programmatic focus. Never usetabindexgreater than 0, and avoidtabindexon non-interactive content. -
Dialogs and overlays manage focus. Move focus into the dialog on open, keep it inside while open, and restore it to the trigger on close. Use
aria-modal="true"on modal dialogs. Native<dialog>with.showModal()does this for you.
I. ARIA
-
Four rules of ARIA.
a. Prefer native HTML elements and attributes over ARIA — do not add ARIA when native HTML already provides the semantics. b. Do not change native semantics unless absolutely necessary. If you need a tab, do not write
<h2 role="tab">; use<div role="tab"><h2>…</h2></div>. c. All interactive ARIA controls must be keyboard usable. d. Never applyaria-hidden="true"orrole="presentation"to a focusable element. -
Accessible names. Precedence:
aria-labelledby>aria-label> native mechanism (label,alt,caption,legend) >title/placeholderfallback. Prefer visible text and native techniques. Do not include role names in accessible names (e.g. "Submit button" creates duplicate output — the role is announced automatically). -
Accessible state and properties. Use
aria-expandedfor toggleable sections,aria-controlsto reference the controlled element,aria-currentfor the current item in a set,aria-selectedfor tab/listbox selection,aria-hiddento hide decorative or offscreen content from the accessibility tree (only on non-focusable elements). -
Live regions for dynamic content. Use
aria-live="polite"for content that updates without user action (feeds, stock tickers). Usearia-live="assertive"sparingly for urgent, time-sensitive messages. Preferrole="status"androle="alert"over rawaria-live, and do not putaria-liveon regions that never update dynamically.
Present Results to User
Group findings by rule section (A–I), worst first. For each finding:
**[Section] Rule name — severity**
- **Where:** file / selector / element
- **What:** the violation, in one sentence
- **Fix:** concrete corrected markup or behaviour
End with a one-line summary: overall pass/fail and the single worst issue to fix first. Never assert conformance for anything you did not verify.
End-User Installation
npx skills add honoluluhenk/agent-skills --skill semantic-html
Claude Code:
cp -r skills/semantic-html ~/.claude/skills/
claude.ai:
Add the skill to project knowledge or paste SKILL.md contents into the conversation.
Files included
- references/examples.md
- references/wcag-and-aria.md
- SKILL.md

