Skills-md category
Frontend Development Skills-md for AI Agents, Claude & Codex
Frontend development skills-md are SKILL.md files that teach Claude, Codex, Cursor and other AI agents to build and fix web interfaces to a professional standard. Each skill audits before it edits, follows fixed rules instead of taste, changes code in small batches you approve, and ships a checker script so the result can be verified. 23 skills are published so far, 4 in HTML and Semantics, 10 in CSS and Layout, 4 in Accessibility and 5 in JavaScript Fundamentals, in a category planned as 13 subcategories.
By Afeez Adebayo, Marketing, SEO & Growth Expert with 10+ years of experience.
Created 23 October 2026. Updated 25 October 2026. Free to use under CC BY 4.0.
Choose a subcategory on the left, pick a skill, and read the full file on the right. Copy it or download it as a .md file without leaving the page.
8 more skills in this set are being written to the same standard and will be added as they are checked.
7 more skills in this set are being written to the same standard and will be added as they are checked.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
This set is being written to the same standard as the published sets. Each one will be checked against the platform documentation it depends on before it is published.
---
name: semantic-html
description: "Audits existing HTML for semantic problems and fixes them in small approved batches without breaking styling, scripts, tests or analytics. Runs a read-only standard-library checker that flags clickable divs, links used as buttons, unnamed buttons and links, nested controls, skipped headings, missing main landmark, missing lang, unlabelled navs and images without alt, then applies fixed decision rules for links versus buttons, landmarks, headings, alt text, lists, tables and ARIA, and verifies with the checker, a keyboard pass and a screen reader spot check. Works on plain HTML and rendered React, Vue, Svelte or Angular output. Use whenever someone asks to audit or refactor markup, fix div soup, review a pull request for semantic HTML, choose between a link and a button, fix heading order or landmarks, or add alt text. Do NOT use for form labels, autocomplete or validation (use html-forms), full WCAG or colour-contrast audits, legal conformance statements, SEO metadata or CSS layout."
license: CC-BY-4.0
metadata:
author: Afeez Adebayo
author_url: https://afeezadebayo.com
author_linkedin: https://www.linkedin.com/in/afeez-adebayo/
author_x: https://x.com/za_icon
source: https://afeezadebayo.com/skills-md/frontend-development/html-semantics/semantic-html/
category: frontend-development
subcategory: html-semantics
version: "1.0.0"
created: "2026-10-23"
updated: "2026-10-23"
---
# Semantic HTML: Audit and Fix Markup Without Breaking the Page
Most markup problems are invisible to the person who wrote them. A `div` with a click handler works with a mouse. A link with `href="#"` opens the chat window. A heading chosen for its font size looks right. Each one fails for keyboard and screen reader users, and each one is easy to miss in review.
This skill makes an agent audit existing HTML, choose the right element for each problem with fixed decision rules, and change the markup in small, approved batches that keep the page's styling, scripts and tracking working. It runs a short read-only checker first, so the work starts from a list of line numbers instead of a guess.
It works on plain HTML and on the rendered output of any framework. Framework notes and tool facts sit in the appendix.
## When to use this skill, and when not to
Use it when the user wants to:
- Audit a page, template or component for semantic problems: missing landmarks, skipped headings, clickable `div`s, links used as buttons, unnamed buttons, missing `alt`.
- Refactor "div soup" into meaningful elements.
- Review a pull request or generated UI code for markup quality.
- Decide between `<a>` and `<button>`, `section` and `div`, or a list and plain paragraphs.
Do not use it for these jobs:
| Request | Use instead |
|---|---|
| Labels, autocomplete, validation and errors in forms | `html-forms.md` |
| Colour contrast, focus styling, motion, or a full WCAG audit | An accessibility audit skill. This skill covers markup only |
| Page titles, meta descriptions and structured data for search | `title-tags-meta-descriptions.md`, `structured-data.md` |
| Visual layout and CSS architecture | Not covered |
## Guardrails that apply to every run
1. **Propose, then change.** The agent reports and proposes first. It edits files only after the user approves a batch, and only on a branch or working copy under version control. It never commits to the main branch, pushes, merges or deploys.
2. **Batches stay small.** At most 10 files or 30 element changes per batch (defaults). Each batch is shown as a diff before it is applied.
3. **Behaviour is preserved.** Every element swap is checked against the CSS selectors, scripts, tests and analytics triggers that target it (step 5). If a swap would break one and the fix is outside the files in scope, the agent stops and asks.
4. **Native before ARIA.** The agent does not add a `role` to make a non-interactive element behave like a control when a native element exists.
5. **Personal data and secrets.** Rendered HTML from logged-in pages can hold names, emails, account numbers, CSRF tokens in hidden inputs and API keys in inline scripts. Run the checker locally. Before sharing any HTML with an external service or pasting it into a prompt, remove inline scripts and the values of hidden inputs, and ask the user. Reports quote line numbers and element names, not page text.
6. **Nothing is invented.** Thresholds in this file are labelled defaults. Tool facts carry a source and the date read. Version-dependent facts carry **verify before relying on this**.
7. **Not legal advice.** The skill improves markup. It does not certify conformance with WCAG or any accessibility law. If the user needs a compliance statement, route it to a qualified human auditor.
8. **Scope boundary.** The agent refuses to rewrite copy, redesign layouts, remove content, or add ARIA to hide a problem it was asked to fix.
## Inputs the agent must have before starting
Ask for what is missing in one message and wait. Do not proceed on assumptions.
| # | Input | What to ask if missing |
|---|---|---|
| 1 | Target | "Which pages, templates or components should I check? Paths or URLs, please." |
| 2 | Stack | "Is this plain HTML, a server template (for example Django, Rails, Twig) or a framework (React, Vue, Svelte, Angular)?" |
| 3 | Rendered output | "Can you save the rendered HTML of each page (browser Save As, or the element's outer HTML from devtools)? The checker reads rendered HTML most reliably." |
| 4 | Safety net | "Is the code in version control, and can I work on a branch?" |
| 5 | Dependants | "Do any CSS files, scripts, tests or tag manager triggers target these elements by tag or class?" |
| 6 | Logged-in pages | "Do any pages show personal or account data when rendered?" |
| 7 | Test tools | "Can you run Python 3 locally, and do you have axe or another automated checker available?" |
If input 4 is no, the agent stops after the report and proposes changes as text only.
## Workflow
### Step 0: Confirm scope and safety
1. Confirm inputs 1 to 7.
2. Confirm the branch. Record the commit the work starts from.
3. Tell the user what will happen: check, triage, decisions, a change plan, approved batches, verification, report.
4. Gate 1: wait for a yes.
### Step 1: Run the checker
1. Save `scripts/semantic_check.py` from this skill folder. It uses only the Python standard library, reads files and writes nothing.
2. Run it on the rendered HTML: `python3 scripts/semantic_check.py page.html`.
3. If only templates are available, run it on them and add "templates only, rendered output not checked" to the report. Template syntax can hide or invent elements.
4. Keep the output. It is the baseline for step 7.
The checker reports these codes. Each line gives the file, line number, level and code.
| Code | Level | Meaning |
|---|---|---|
| `click-on-non-interactive` | error | A `div`, `span`, `li`, `td`, `p`, `img`, `section` or `article` has `onclick`, `@click`, `v-on:click`, `(click)` or `on:click` |
| `link-used-as-button` | error | `href` is empty, `#` or `javascript:` |
| `link-without-href` | error | `<a>` with no `href` cannot take keyboard focus |
| `button-without-name`, `a-without-name` | error | No text, image `alt`, `aria-label`, `aria-labelledby` or `title` |
| `nested-interactive` | error | A link or button inside another link or button |
| `img-missing-alt` | error | `<img>` with no `alt` attribute at all |
| `heading-skip` | error | A heading jumps down more than one level |
| `main-count` | error | Not exactly one `main` landmark |
| `missing-lang` | error | `<html>` has no `lang` |
| `no-h1` | warn | No `h1` on the page |
| `unlabelled-nav` | warn | More than one `nav` and at least one has no label |
| `role-on-non-interactive` | warn | `role="button"` or `role="link"` on a non-interactive element |
| `positive-tabindex` | warn | `tabindex` above 0 changes the tab order |
The checker cannot judge meaning. It does not know whether a heading describes its section or whether `alt` text is useful. Steps 3 and 7 cover that.
### Step 2: Triage
Sort every flag into one of four priority groups. Fix in this order.
| Priority | Codes | Why first |
|---|---|---|
| P1: controls | `click-on-non-interactive`, `link-used-as-button`, `link-without-href`, `*-without-name`, `nested-interactive` | Keyboard and screen reader users cannot reach or understand the control |
| P2: page structure | `main-count`, `missing-lang`, `heading-skip`, `no-h1`, `unlabelled-nav` | Users cannot move around the page or hear it in the right language |
| P3: images | `img-missing-alt` | Content or function is missing for screen reader users |
| P4: order | `positive-tabindex`, `role-on-non-interactive` | Behaviour is unexpected but usually still usable |
Form fields go to `html-forms.md`. List them in the report and do not fix them here.
### Step 3: Decide the element
Use these rules. They are deterministic: the same situation always gets the same element.
**Controls.**
| Situation | Element |
|---|---|
| It changes the URL or loads another page or file | `<a href="real-url">` |
| It does something on this page (opens a dialog, adds to basket, toggles a panel) | `<button type="button">` |
| It submits a form | `<button type="submit">` |
| It shows and hides a section of content with no script needed | `<details>` and `<summary>` |
| It must look like a link but performs an action | `<button type="button">` styled as a link |
| It must look like a button but goes to another page | `<a href>` styled as a button |
The test is "does the URL change?" A link changes the URL. A button does not. Never put a button inside a link, or a link inside a button: pick one element from the table.
**Landmarks.**
| Region | Element | Rule |
|---|---|---|
| Main content | `<main>` | Exactly one per page |
| Site header | `<header>` | Top level of `body`, not inside `main` or `article` |
| Site footer | `<footer>` | Top level of `body` |
| Navigation blocks | `<nav>` | If there is more than one, give each a distinct `aria-label` such as "Main" and "Legal" |
| Related content beside the main content | `<aside>` | Only for content that makes sense apart from the main content |
| A self-contained item (post, product card that stands alone, comment) | `<article>` | It would make sense if lifted on its own |
| A themed group with its own heading | `<section>` | Only when it has a heading. Otherwise use `<div>` |
**Headings.**
1. One `h1` per page, naming what the page is about (default rule).
2. Never skip a level going down: `h2` follows `h1`, `h3` follows `h2`. Going back up any number of levels is fine.
3. Choose the level by the section's place in the outline, never by font size. Change the size in CSS.
4. A heading must describe the content beneath it. A styled sentence that introduces no section is a paragraph.
Do not rely on sectioning elements to change heading levels. The WHATWG spec replaced its outline algorithm in 2022 because no browser implemented it, so an `h1` inside a `section` is still read as an `h1`.
**Images.**
| Image role | `alt` |
|---|---|
| Carries information | Describe the information, not the picture: "Sales doubled between 2024 and 2025" |
| Decorative | `alt=""`, so screen readers skip it |
| The only content of a link or button | Describe the action or destination: "Close", "Home" |
| A complex chart or diagram | A short `alt`, with the full description or data in nearby text |
Never remove the `alt` attribute to mark an image as decorative. A missing `alt` and an empty `alt` behave differently.
**Lists and tables.**
- Items of the same kind in a row or column (menu links, features, steps) go in `ul` or `ol`. A card grid does not need to be a list unless the count or order helps the user.
- A table holds data with rows and columns. Use `th` with `scope="col"` or `scope="row"`. If a table is only for layout, replace it with CSS.
**ARIA.**
1. If a native element does the job, use it and add no role.
2. Add ARIA only for patterns with no native element (tabs, a combobox), and then the element must also get the keyboard behaviour the role promises.
3. `aria-label` on a button or link is for an icon-only control. Do not use it to override visible text.
### Step 4: Write the change plan
For every flag, write one row: file and line, current element, new element, reason (a rule from step 3), and dependants found in step 5. Group the rows into batches of at most 10 files or 30 changes.
### Step 5: Check dependants before each swap
Search the codebase for every tag and class involved. Use the commands in the Templates section.
| Dependant | What breaks | What to do |
|---|---|---|
| CSS selectors by tag (`div.card`, `nav > div`) | Styling disappears | Update the selector in the same batch |
| Button default styles | The new button shows a grey box | Add the button reset from the Templates section |
| Scripts that query by tag or check `tagName` | Handlers stop firing | Update the selector. Keep the class names |
| Event handlers on the old element | Double handling, or Enter fires twice | Remove the manual keyboard handler when moving to a native button |
| `<button>` inside a `<form>` | It submits the form | Always set `type="button"` unless it submits |
| Tests that select by tag or text | Tests fail | Update selectors. Prefer selecting by role and name |
| Tag manager triggers (click classes, element selectors) | Analytics events stop | List them for the user. The agent does not change tag manager settings |
If a dependant sits outside the files in scope, stop and ask the user before changing it.
### Step 6: Apply one batch at a time
1. Show the diff for the batch.
2. Gate 2: wait for a yes for this batch.
3. Apply the batch on the branch.
4. Run step 7 before the next batch.
### Step 7: Verify
1. **Checker.** Re-run `semantic_check.py`. Every flag fixed in the batch must be gone, and no new error may appear.
2. **Keyboard.** Using only the keyboard, Tab through the changed area. Every control receives focus in reading order with a visible focus indicator. Enter activates links. Enter and Space activate buttons.
3. **Screen reader spot check.** Open the headings list and the landmarks list in a screen reader (the rotor in VoiceOver, the elements list in NVDA). Headings form a sensible outline. There is one main region and each navigation has a distinct name.
4. **Automated rules.** Run axe or the team's equivalent on the changed pages. Zero new violations.
5. **Visual.** Compare screenshots before and after. Layout must not shift unless the user approved it.
6. **Tests.** The project's existing tests pass.
Automated checks find only a share of problems. The WebAIM Million 2026 report counted detectable failures on 95.9% of one million home pages and put full conformance at below 4.1%, because only automatically detectable failures were counted. Steps 7.2 and 7.3 are not optional.
### Step 8: Report
Use the report template. State what changed, what is left, what was handed to `html-forms.md`, and what was not checked.
## Worked example
The page below is invented. The checker output is real: it was produced by running the script in this skill on these files.
**Input.** A pricing page, plain HTML, under version control. No CSS targets `div.card` by tag. A tag manager trigger listens for clicks on `.card`.
```html
<!doctype html>
<html>
<head><title>Plans</title></head>
<body>
<div class="top">
<nav><a href="/">Home</a> <a href="/pricing">Pricing</a></nav>
</div>
<div class="content">
<h1>Choose a plan</h1>
<h3>Monthly</h3>
<div class="card" onclick="selectPlan('pro')">Pro plan</div>
<a href="#" onclick="openChat()">Talk to sales</a>
<button class="icon-close"><svg aria-hidden="true"></svg></button>
<img src="/badge.png">
<a href="/terms"><button>Read terms</button></a>
</div>
<div class="footer"><nav><a href="/privacy">Privacy</a></nav></div>
</body>
</html>
```
**Step 1, checker output** (tabs shown as spaces):
```
before.html:1 error main-count 0 main landmarks; expected 1
before.html:1 error missing-lang <html> has no lang
before.html:1 warn unlabelled-nav 2 nav elements, not all labelled
before.html:10 error heading-skip h1 followed by h3
before.html:11 error click-on-non-interactive <div> has a click handler; use <button> or <a href>
before.html:12 error link-used-as-button href="#"; actions belong in <button>
before.html:13 error button-without-name no text, alt or aria-label
before.html:14 error img-missing-alt /badge.png
before.html:15 error nested-interactive <button> inside another link or button
before.html: 8 errors, 1 warnings
```
**Steps 2 and 3, decisions.**
| Line | Decision | Rule |
|---|---|---|
| 11 | `<button type="button" class="card">` | Selecting a plan stays on the page |
| 12 | `<button type="button">` styled as a link | Opening chat does not change the URL |
| 13 | `aria-label="Close"` | Icon-only control |
| 15 | Keep the link, drop the inner button | "Read terms" goes to another page |
| 10 | `h3` becomes `h2` | No skipped levels |
| 14 | `alt=""` | The user confirms the badge is decorative |
| Structure | `header`, `main`, `footer`; `lang="en-GB"`; navs labelled "Main" and "Legal" | Landmark rules |
**Step 5, dependants.** The `.card` class stays, so the tag manager trigger keeps firing. The agent lists it anyway for the user to confirm. The new buttons get the reset styles. `selectPlan` and `openChat` move from inline attributes to listeners on `data-plan` and `data-action`, so the agent shows that script change in the same batch.
**After (one batch, approved):**
```html
<!doctype html>
<html lang="en-GB">
<head><title>Plans</title></head>
<body>
<header>
<nav aria-label="Main"><a href="/">Home</a> <a href="/pricing">Pricing</a></nav>
</header>
<main>
<h1>Choose a plan</h1>
<h2>Monthly</h2>
<button type="button" class="card" data-plan="pro">Pro plan</button>
<button type="button" class="link-style" data-action="chat">Talk to sales</button>
<button type="button" class="icon-close" aria-label="Close"><svg aria-hidden="true"></svg></button>
<img src="/badge.png" alt="">
<a href="/terms">Read terms</a>
</main>
<footer><nav aria-label="Legal"><a href="/privacy">Privacy</a></nav></footer>
</body>
</html>
```
**Step 7, checker output:** `after.html: 0 errors, 0 warnings`. The user then runs the keyboard and screen reader checks and confirms them. The report lists one item for the user: confirm the `.card` click trigger still fires in the tag manager preview.
## Templates
### Checker
`scripts/semantic_check.py` ships with this skill. Usage:
```
python3 scripts/semantic_check.py page.html other.html
```
It exits with status 1 if any error is found, so it can run in CI. Read it before running it.
### Finding dependants
```
grep -rnE "div\.card|\.card\b" --include=*.css --include=*.scss src/
grep -rnE "querySelector(All)?\(['\"][^'\"]*card|tagName" --include=*.js --include=*.ts src/
grep -rnE "getByText|querySelector|\.card" --include=*.test.* --include=*.spec.* .
```
Replace `card` with the class or tag being changed.
### Button reset
```css
button.link-style,
button.card {
appearance: none;
background: none;
border: 0;
padding: 0;
font: inherit;
color: inherit;
text-align: inherit;
cursor: pointer;
}
button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
```
### Keyboard check
```
[ ] Tab reaches every control in the changed area, in reading order
[ ] Focus is visible on every control
[ ] Enter follows every link
[ ] Enter and Space activate every button
[ ] No control is reached that should not be (hidden, decorative)
[ ] Shift+Tab moves back in the same order
```
### Report
```
SEMANTIC HTML REPORT: [files], [date], branch [name] from [commit]
Baseline: [n] errors, [n] warnings
Fixed this run: [n] (P1 [n], P2 [n], P3 [n], P4 [n])
Remaining: [list with reason]
Handed to html-forms: [n] form fields
Dependants changed: [CSS, scripts, tests]
Dependants for the user: [tag manager triggers, files out of scope]
Verification: checker [0 errors], keyboard [pass/fail], screen reader [pass/fail],
automated rules [n new violations], visual [no shift], tests [pass]
Not checked: [rendered output, colour contrast, focus styles beyond changed area]
This report is not a statement of WCAG or legal conformance.
```
### Starting prompt
```
Use the semantic-html skill on [files]. The stack is [stack]. Work on the
branch [name]. Start with the checker and a change plan, and do not edit
anything until I approve a batch.
```
## Failure modes and anti-patterns
| # | Failure | How to spot it | What to do instead |
|---|---|---|---|
| 1 | ARIA patched onto a `div` | `role="button"` and `tabindex="0"` added, but no Enter or Space handling and no disabled state | Replace with `<button type="button">` and a style reset. A native button brings focus, keyboard activation and form behaviour |
| 2 | Heading levels picked for size | `h4` used because it "looks right"; the checker flags `heading-skip` | Pick the level from the outline. Move size into CSS classes |
| 3 | A swap breaks styling, scripts or tracking | Visual diff shows a grey box; a click handler stops; an analytics event stops | Run step 5 before each swap. Keep class names. List tag manager triggers for the user |
| 4 | An automated pass treated as done | The report says "0 errors" and nobody used a keyboard | Run steps 7.2 and 7.3 every time. The checker and axe catch only what can be detected by rule |
| 5 | Links and buttons mixed up | A button inside a link, `href="#"` for actions, a `<button>` that navigates with script | Ask "does the URL change?" and use the table in step 3 |
## Quality bar
Check every item before handing over.
1. The user approved gate 1, and the work is on a named branch.
2. The baseline checker output is saved and quoted in the report.
3. Every flag is in a priority group, fixed, handed to `html-forms.md`, or listed as remaining with a reason.
4. Every element decision cites a rule from step 3.
5. Every batch had at most 10 files or 30 changes and was approved before it was applied.
6. Every `<button>` added has an explicit `type`.
7. Dependants were searched for each changed tag and class, and the result is in the report.
8. The checker shows zero errors in the changed files, with no new errors elsewhere.
9. The keyboard check was run on the changed area and its result is recorded.
10. No `role` was added where a native element exists.
11. No page text, hidden input value or inline script content appears in the report.
12. The report says it is not a conformance statement.
## Cost and effort
The checker runs locally and makes no network calls. The agent reads its output and only the lines it flags, so token use grows with the number of problems, not the size of the page. The cheaper path for a large site is to check templates or shared components first, because one fix there repairs every page that uses them.
## Handoffs to related skills
`html-forms.md` handles every form field the checker or triage surfaces. `core-web-vitals.md` and `javascript-seo.md` cover performance and rendering for search. `structured-data.md` covers schema markup. `ai-evals-testing.md` helps if the team wants to test an agent's markup output at scale.
## Appendix: tool-specific notes
Every fact below was read on 23 October 2026. **Verify before relying on this**: tools and rules change.
### Frameworks
- The checker uses Python's `html.parser`, which lowercases attribute names, so React's `onClick` is read as `onclick`. It also recognises Vue's `@click` and `v-on:click`, Svelte's `on:click` and Angular's `(click)`.
- JSX and template syntax can confuse an HTML parser. Prefer the rendered HTML. When you must check templates, treat results as a first pass.
- Svelte and Vue components keep their directives when an element changes. Keep bindings, keys and component boundaries intact.
### axe-core
Deque's rule `button-name` (axe-core 4.11) checks that buttons and elements with `role="button"` have an accessible name. It maps to WCAG 4.1.2 Name, Role, Value (Level A) and is rated critical impact. Fixes it accepts: inner text, a non-empty `aria-label`, or `aria-labelledby` pointing at text. Input buttons are covered by a separate rule, `input-button-name`.
### WHATWG outline algorithm
The HTML spec replaced its document outline algorithm with one based on heading levels in 2022 (WHATWG pull request 7829, reported by Bruce Lawson on 7 July 2022). No browser had implemented the old algorithm, so nesting an `h1` in `section` never changed its level.
### Claude Agent Skills
Anthropic limits `name` to 64 characters and `description` to 1,024. Claude Code documents `disable-model-invocation: true` for skills with side effects, so they run only when the user calls them. This skill edits files, so that setting suits teams that want manual control. Install skills only from sources you trust.
## Sources
Last verified 23 October 2026 for every source below, except where a date says otherwise.
- WebAIM, The WebAIM Million (2026 report, February 2026 data): https://webaim.org/projects/million/. Failure rates and the ARIA error correlation.
- W3C WAI, Page Structure tutorial: https://www.w3.org/WAI/tutorials/page-structure/. Regions, labels, headings and WCAG mapping.
- W3C WAI, Forms tutorial (updated 27 March 2026): https://www.w3.org/WAI/tutorials/forms/. Used for the handoff boundary.
- Deque University, axe rule button-name (axe-core 4.11): https://dequeuniversity.com/rules/axe/4.11/button-name.
- Bruce Lawson, Why the HTML outlining algorithm was removed from the spec (7 July 2022): https://brucelawson.co.uk/2022/why-the-html-outlining-algorithm-was-removed-from-the-spec-the-truth-will-shock-you/.
- Ben Myers, post on clickable divs (30 September 2019): https://benmyers.dev/blog/clickable-divs/. Everything a clickable `div` needs.
- GrahamTheDev, They...just...won't...learn (27 May 2021, edited 17 December 2021): https://dev.to/grahamthedev/they-just-won-t-learn-a-button-is-a-lt-button-gt-accessibility-rants-k1b. The URL-change rule and why developers reach for `div`s.
- joabgonzalez, ai-agents-skills, html skill (via skills.cat): https://skills.cat/skills/joabgonzalez/ai-agents-skills/html. Rival implementation.
- stolinski, s-stack, html skill (via skillselion): https://skillselion.com/skills/stolinski/s-stack/html. Rival implementation.
- 5dlabs, cto-agents, web-design-guidelines (via skills.sh): https://www.skills.sh/5dlabs/cto-agents/web-design-guidelines. Rival listing, rules not visible.
- Anthropic, Agent Skills best practices (read 22 October 2026): https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices.
- Claude Code documentation, Skills (read 22 October 2026): https://code.claude.com/docs/en/skills.
---
Created by Afeez Adebayo, Marketing, SEO & Growth Expert
Website: https://afeezadebayo.com
LinkedIn: https://www.linkedin.com/in/afeez-adebayo/
X: https://x.com/za_icon
Source: https://afeezadebayo.com/skills-md/frontend-development/html-semantics/semantic-html/
Licence: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). You may copy, share and adapt this skill, including for commercial use, as long as you credit Afeez Adebayo and link to the source URL above. Keep this notice in any copy or adapted version.
What frontend skills do for an AI agent
AI coding tools write a lot of frontend code, and much of it works only for the person who tested it with a mouse. A generated pricing card is a clickable div. A sign-in form turns autofill off. A heading is picked for its size. The page looks finished and fails keyboard users, screen reader users and password managers.
These skills change how the agent works in three ways. It measures first, with a short read-only script that reports problems by line number. It decides with fixed rules, such as “if the URL changes, use a link; if it does not, use a button”. And it changes code only in small batches on a branch, after checking the CSS, scripts, tests and tracking that depend on the markup. The WebAIM Million 2026 report found detectable accessibility failures on 95.9% of one million home pages, so there is plenty for an agent to fix.
The 13 frontend skill sets
The category is planned as 13 sets, built in order of how basic and in-demand they are. HTML and Semantics is live with 4 skills, CSS and Layout with 10 of a planned 12 and Accessibility with 4 of a planned 12 and JavaScript Fundamentals with 5 of a planned 12, and the rest follow set by set. UI/UX Design will follow as its own category once this one is complete.
01. HTML and Semantics
Four published skills: Semantic HTML for links, buttons, headings and landmarks, HTML Forms for labels, autofill and validation, Responsive Images for lazy loading, srcset and alt text, and Dialog and Popover for native modals, focus and Esc handling. Each ships a checker script. Start here, because every other frontend skill assumes the markup is sound.
02. CSS and Layout
Ten published skills so far: Flexbox and Grid Layout for overflow, 1fr blowouts and truncation, Cascade Layers for rules that lose to other rules and migrations to @layer, Container Queries for components that respond to their container, Fluid Type and Spacing for clamp() sizes that fail 500% zoom, Viewport Units for 100vh heroes and modals on mobile, Modern CSS Selectors for :has(), :is() and :where() specificity bugs, CSS Nesting for native nesting that silently fails, CSS Custom Properties for undefined var() names, bad fallbacks and ignored @property rules, CSS Animations and Transitions for transition: all, reduced motion and display fades, and CSS Logical Properties for margin-left, padding-right and Tailwind ml- classes that break right-to-left layouts. Each ships a checker script, and two more are planned.
03. Accessibility
Four published skills so far: Colour Contrast for WCAG 2.2 text, border and focus-ring ratios, Keyboard Focus for tab order, focus rings and focus hidden under sticky content, ARIA Names and Roles for unnamed controls and misused roles, and ARIA Live Announcements for silent toasts and status messages. Each ships a checker script, and eight more are planned.
04. JavaScript Fundamentals
Five published skills so far: Promises and Async/Await for floating promises, forEach(async) loops, the wrong Promise combinator and swallowed errors, AbortController Cancellation for fetches with no signal, timeouts that leave work running, leaking abort listeners and stale responses, Yield to the Main Thread for long tasks, yields that never pause and missing Safari fallbacks, JavaScript Error Handling for empty catch blocks, lost causes, unchecked fetch responses and global handlers, and Dynamic Import and Code Splitting for failed chunk loads, stale chunks after a deploy and lazy() setup. Each ships a scanner script, and seven more are planned.
05. TypeScript
Planned. Typing rules and migrations an agent can verify.
06. React and Component Frameworks
Planned. Component structure and framework patterns for React and similar libraries.
07. State and Data Fetching
Planned. Client state, server data, and loading and error handling.
08. Web Performance
Planned. Loading and rendering work, measured before and after each change.
09. Frontend Testing
Planned. Unit, component and end-to-end tests an agent can write and run.
10. Build Tools and Tooling
Planned. Bundlers, linters and project setup.
11. Design Systems and Component Libraries
Planned. Tokens, components and documentation for shared interfaces.
12. Frontend Security
Planned. Common client-side vulnerabilities and safe handling of user input.
13. Rendering and SEO
Planned. Server and client rendering choices that keep pages crawlable.
Which frontend skills to install first, by problem
Start with the problem you have today.
- Reviewing AI-generated or inherited markup: install Semantic HTML. It finds clickable divs, links used as buttons, unnamed icon buttons, skipped headings and missing landmarks.
- Fixing a sign-in, sign-up or checkout form: install HTML Forms. It sets the right input types and autocomplete tokens, groups radio buttons and writes error messages that say how to fix the problem.
- Fixing images on a page: install Responsive Images. It fixes lazy-loaded hero images, srcset, sizes, picture elements and alt text, with a checker and a sizes calculator.
- Replacing div modals and menus: install Dialog and Popover. It swaps div modals for native dialogs and fixes popover targets, focus, Esc and scroll lock.
For CSS, use Flexbox and Grid Layout when a page scrolls sideways, Cascade Layers when one rule keeps losing to another, and Container Queries when a component should respond to its container.
Semantic HTML and HTML Forms hand work to each other, so installing both costs nothing extra.
How to use frontend skills with Claude and Codex: a worked example
A developer asks an agent to tidy a pricing page. With the Semantic HTML skill loaded, the agent runs its checker and reports 8 errors and 1 warning: no main landmark, no language, a skipped heading, a clickable div, a link used to open chat, an icon button with no name, an image with no alt text and a button inside a link.
It proposes one batch: two buttons in place of the div and the chat link, a label on the icon button, the right heading level and labelled landmarks. It keeps every class name, so the styling and a tag manager trigger still work. After approval, the checker reports 0 errors and the developer runs a quick keyboard pass to confirm.
How these skills are written and checked
Each skill starts from a research pass of at least 15 sources: official documentation such as MDN and the W3C, primary research such as the WebAIM Million, practitioner writing, and the best public skills on the same task. Every skill has to beat the three strongest of those on something concrete, such as a failure mode they miss or a verification step they leave out.
Every figure carries a source and a date, every threshold is labelled as a default, and any checker script is tested on example files before it is published. Skills never push, merge or deploy, and they never claim legal accessibility conformance.
Frequently asked questions
What is a frontend development SKILL.md file?
It is a plain Markdown file with a name, a description and a set of instructions that an AI agent loads when a task matches, such as auditing markup or fixing a form. These files also bundle a small checker script, so the agent can measure problems before and after it changes code instead of guessing.
Which AI agents can use these skills?
Claude, Claude Code and OpenAI Codex read SKILL.md files from their skills folders, and Cursor can load them as skills or project rules. Any agent that accepts custom instructions can use the body of the file. The checker scripts need Python 3 and use only its standard library.
Which frontend skills are published now?
Twenty skills are published. HTML and Semantics has four: Semantic HTML, HTML Forms, Responsive Images and Dialog and Popover. CSS and Layout has ten: Flexbox and Grid Layout, Cascade Layers, Container Queries, Fluid Type and Spacing, Viewport Units, Modern CSS Selectors, CSS Nesting, CSS Custom Properties, CSS Animations and Transitions and CSS Logical Properties. Accessibility has four: Colour Contrast, Keyboard Focus, ARIA Names and Roles and ARIA Live Announcements. JavaScript Fundamentals has two: Promises and Async/Await and AbortController Cancellation. The other 9 sets will be released one at a time.
Will the agent change my code without asking?
No. Every skill in this category reports and plans first, works on a branch, and changes files only in small batches you approve after seeing the diff. The skills never push, merge or deploy, and they stop to ask if a fix would reach files outside the agreed scope.
Do these skills make my site accessible or compliant?
They fix many common problems and verify the result with a checker, a keyboard pass and a screen reader spot check. They do not certify conformance with WCAG or any accessibility law. Automated checks only find what rules can detect, so a qualified person should audit anything that needs a compliance statement.
Do the skills work with React, Vue and other frameworks?
Yes. The checkers read rendered HTML, which every framework produces, and they recognise the click attributes of React, Vue, Svelte and Angular. The rules are about the HTML the browser receives, so they apply whichever library built it. When only templates or JSX are available, the skills treat the checker results as a first pass and say so in the report.
Are these skills free?
Yes. Every skill is free to use, adapt and share under CC BY 4.0, including for commercial work, as long as you credit Afeez Adebayo and link to the skill’s page. Copy a file, download it with its checker script, or adapt it for your team’s own conventions.
