Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/components/Accesskeys.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// accesslint-031: Accesskeys — duplicate accesskey values
export default function Accesskeys() {
return (
<nav>
<a href="/home" accessKey="h">Home</a>
<a href="/help" accessKey="h">Help</a>
<a href="/search" accessKey="s">Search</a>
<a href="/settings" accessKey="s">Settings</a>
</nav>
);
}
14 changes: 14 additions & 0 deletions src/components/Accordion.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// accesslint-034: Empty Heading — heading used as accordion trigger with no text
// accesslint-075: Button Name — empty button
export default function Accordion() {
return (
<div>
<h3><button></button></h3>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practice: Heading is empty. Add text content or remove the heading element.

Headings must have discernible text.

Details

Following content: "Accordion panel 1 content."

Screen reader users navigate pages by headings, so empty headings create confusing navigation points. Ensure all headings contain visible text or accessible names. If a heading is used purely for visual styling, use CSS instead of heading elements.


WCAG 4.1.2: Button has no discernible text.

Buttons must have discernible text.

Details

Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.

<div>Accordion panel 1 content.</div>
<h3><button></button></h3>
<div>Accordion panel 2 content.</div>
<h3><button></button></h3>
<div>Accordion panel 3 content.</div>
</div>
);
}
10 changes: 10 additions & 0 deletions src/components/AriaAllowed.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// accesslint-058: ARIA Allowed Attr — ARIA attributes not allowed for role
export default function AriaAllowed() {
return (
<div>
<h2 aria-checked="true">Heading with aria-checked</h2>
Copy link
Copy Markdown

@accesslint accesslint Bot Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: ARIA attribute "aria-checked" is not allowed on role "heading".

ARIA attributes must be allowed for the element's role.

Details

Attribute: aria-checked="true", role: heading, allowed role-specific attributes: aria-level

Each ARIA role supports specific attributes. Using unsupported attributes creates confusion for assistive technologies. Check the ARIA specification for which attributes are valid for each role, or remove the attribute if it's not needed.

Also on line 7.

<p aria-selected="true">Paragraph with aria-selected</p>
<img src="/photo.jpg" alt="Photo" aria-expanded="true" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practice: Alt text "Photo" contains redundant word(s): photo.

Image alt text should not contain words like 'image', 'photo', or 'picture' — screen readers already announce the element type.

Details

Current alt: "Photo", redundant word(s): photo

Screen readers already announce 'image' or 'graphic' before reading alt text, so phrases like 'image of', 'photo of', or 'picture of' are redundant. Remove these words and describe what the image shows. For example, change 'image of a dog' to 'golden retriever playing fetch'.


WCAG 4.1.2: ARIA attribute "aria-checked" is not allowed on role "heading".

</div>
);
}
13 changes: 13 additions & 0 deletions src/components/AriaAttrs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// accesslint-055: ARIA Valid Attr — misspelled ARIA attributes
// accesslint-056: ARIA Valid Attr Value — invalid ARIA attribute values
export default function AriaAttrs() {
return (
<div>
<button aria-expandd="true">Toggle</button>
<input type="text" aria-requird="true" />
Comment on lines +6 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: Invalid ARIA attribute "aria-expandd".

ARIA attributes must be valid (correctly spelled).

Details

Misspelled ARIA attributes are ignored by assistive technologies. Check the spelling against the WAI-ARIA specification. Common mistakes: aria-labeledby (should be aria-labelledby), aria-role (should be role), aria-description (valid in ARIA 1.3+).


WCAG 4.1.2: ARIA attribute "aria-expandd" is not allowed on role "button".

ARIA attributes must be allowed for the element's role.

Details

Attribute: aria-expandd="true", role: button, allowed role-specific attributes: aria-disabled, aria-expanded, aria-haspopup, aria-pressed

Each ARIA role supports specific attributes. Using unsupported attributes creates confusion for assistive technologies. Check the ARIA specification for which attributes are valid for each role, or remove the attribute if it's not needed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: Form element has no accessible label.

Form elements must have labels. Use , aria-label, or aria-labelledby.

Details

type: text

Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.

<div role="checkbox" aria-checked="maybe">Option</div>
<div aria-live="aggressive">Updates here</div>
<button aria-pressed="none">Like</button>
Comment on lines +8 to +10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: aria-checked must be "true", "false", or "mixed", got "maybe".

ARIA attributes must have valid values.

Details

Each ARIA attribute accepts specific value types. Boolean attributes (aria-hidden, aria-disabled) accept only 'true' or 'false'. Tristate attributes (aria-checked, aria-pressed) also accept 'mixed'. Token attributes (aria-live, aria-autocomplete) accept predefined values. ID reference attributes (aria-labelledby, aria-describedby) must reference existing element IDs.

</div>
);
}
19 changes: 19 additions & 0 deletions src/components/AriaChildren.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// accesslint-060: ARIA Required Children — missing required child roles
export default function AriaChildren() {
return (
<div>
<ul role="tablist">
Copy link
Copy Markdown

@accesslint accesslint Bot Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 1.3.1: Role "tablist" requires children with role: tab.

Certain ARIA roles require specific child roles to be present.

Details

Some ARIA roles represent containers that must contain specific child roles for proper semantics. For example, a list must contain listitems, a menu must contain menuitems. Add the required child elements with appropriate roles, or use native HTML elements that provide these semantics implicitly (e.g.,

    with
  • ).

Also on line 9, line 13.

<li>Tab 1</li>
<li>Tab 2</li>
</ul>
<div role="list">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 1.3.1: Role "tablist" requires children with role: tab.

<span>Item 1</span>
<span>Item 2</span>
</div>
<div role="grid">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 1.3.1: Role "tablist" requires children with role: tab.

<div>Cell 1</div>
<div>Cell 2</div>
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions src/components/AriaCommandNames.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// accesslint-064: ARIA Command Name — command roles without names
// accesslint-065: ARIA Input Field Name — input roles without names
export default function AriaCommandNames() {
return (
<div>
<div role="button"></div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: Button has no discernible text.

Buttons must have discernible text.

Details

Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.

<div role="link"></div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 2.4.4, WCAG 4.1.2: Link has no discernible text.

Links must have discernible text via content, aria-label, or aria-labelledby.

Details

Screen reader users need to know where a link goes. Add descriptive text content, aria-label, or use aria-labelledby. For image links, ensure the image has alt text describing the link destination. Avoid generic text like 'click here' or 'read more'—link text should make sense out of context.

<div role="menuitem"></div>
Comment on lines +6 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 4.1.2: ARIA command has no accessible name.

ARIA commands must have an accessible name.

Details

Interactive ARIA command roles (button, link, menuitem) must have accessible names so users know what action they perform. Add visible text content, aria-label, or aria-labelledby to provide a name.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WCAG 1.3.1: Role "menuitem" must be contained within: menu, menubar, group.

Certain ARIA roles must be contained within specific parent roles.

Details

Some ARIA roles represent items that must exist within specific container roles. For example, a listitem must be within a list, a tab must be within a tablist. Wrap the element in the appropriate parent, or use native HTML elements that provide this structure (e.g.,

  • inside
      ).

  • <div role="textbox"></div>
    <div role="searchbox"></div>
    <div role="spinbutton"></div>
    Comment on lines +9 to +11
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    Form elements must have labels. Use , aria-label, or aria-labelledby.

    Details

    role: textbox

    Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.


    WCAG 4.1.2: ARIA input field has no accessible name.

    ARIA input fields must have an accessible name.

    Details

    ARIA input widgets (combobox, listbox, searchbox, slider, spinbutton, textbox) must have accessible names so users understand what data to enter. Add a visible label with aria-labelledby, or use aria-label if a visible label is not possible.

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Role "spinbutton" requires attribute "aria-valuenow".

    Elements with ARIA roles must have all required ARIA attributes.

    Details

    Some ARIA roles require specific attributes to function correctly. For example, checkbox requires aria-checked, slider requires aria-valuenow, heading requires aria-level. Without these attributes, assistive technologies cannot convey the element's state or value to users. Add the missing required attribute with an appropriate value.

    </div>
    );
    }
    16 changes: 16 additions & 0 deletions src/components/AriaDialogs.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    // accesslint-069: ARIA Dialog Name — dialogs without accessible names
    export default function AriaDialogs() {
    return (
    <div>
    <div role="dialog">
    <p>Are you sure you want to delete this?</p>
    <button>Yes</button>
    <button>No</button>
    </div>
    <div role="alertdialog">
    <p>Session expired.</p>
    <button>OK</button>
    </div>
    </div>
    );
    }
    12 changes: 12 additions & 0 deletions src/components/AriaHiddenFocus.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    // accesslint-063: ARIA Hidden Focus — focusable elements inside aria-hidden
    export default function AriaHiddenFocus() {
    return (
    <div>
    <div aria-hidden="true">
    <button>Hidden but focusable button</button>
    <a href="/secret">Hidden but focusable link</a>
    <input type="text" placeholder="Hidden but focusable input" />
    </div>
    </div>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/AriaMeters.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-067: ARIA Meter Name — meters without accessible names
    // accesslint-068: ARIA Progressbar Name — progressbars without names
    export default function AriaMeters() {
    return (
    <div>
    <div role="meter" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
    Copy link
    Copy Markdown

    @accesslint accesslint Bot Feb 19, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Meter has no accessible name.

    ARIA meter elements must have an accessible name.

    Details

    Meter elements display a value within a known range (like disk usage or password strength). They must have accessible names so screen reader users understand what is being measured. Use aria-label or aria-labelledby to provide context.

    Also on line 8.

    <div role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Progressbar has no accessible name.

    ARIA progressbar elements must have an accessible name.

    Details

    Progress indicators must have accessible names so screen reader users understand what process is being tracked. Use aria-label (e.g., 'File upload progress') or aria-labelledby to reference a visible heading or label.

    <div role="meter" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"></div>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Meter has no accessible name.

    </div>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/AriaParent.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-061: ARIA Required Parent — roles missing required parents
    export default function AriaParent() {
    return (
    <div>
    <div role="tab">Tab without tablist</div>
    <div role="listitem">Item without list</div>
    <div role="option">Option without listbox</div>
    <div role="row">Row without table/grid</div>
    Comment on lines +5 to +8
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1: Role "tab" must be contained within: tablist.

    Certain ARIA roles must be contained within specific parent roles.

    Details

    Some ARIA roles represent items that must exist within specific container roles. For example, a listitem must be within a list, a tab must be within a tablist. Wrap the element in the appropriate parent, or use native HTML elements that provide this structure (e.g.,

  • inside
      ).

  • Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1: Role "row" requires children with role: cell or columnheader or gridcell or rowheader.

    Certain ARIA roles require specific child roles to be present.

    Details

    Some ARIA roles represent containers that must contain specific child roles for proper semantics. For example, a list must contain listitems, a menu must contain menuitems. Add the required child elements with appropriate roles, or use native HTML elements that provide these semantics implicitly (e.g.,

      with
    • ).

    </div>
    );
    }
    10 changes: 10 additions & 0 deletions src/components/AriaProhibited.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    // accesslint-072: ARIA Prohibited Attr — prohibited attributes for roles
    export default function AriaProhibited() {
    return (
    <div>
    <div role="presentation" aria-label="Decorative section">Content</div>
    Copy link
    Copy Markdown

    @accesslint accesslint Bot Feb 19, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: aria-label and aria-labelledby are prohibited on role "presentation".

    ARIA attributes must not be prohibited for the element's role.

    Details

    Some ARIA roles prohibit certain attributes. For example, roles like 'none', 'presentation', 'generic', and text-level roles (code, emphasis, strong) prohibit aria-label and aria-labelledby because naming is not supported for these roles. Remove the prohibited attributes or change the role.

    Also on line 7.

    <div role="none" aria-describedby="desc1">More content</div>
    <img role="presentation" aria-label="Decorative image" src="/bg.png" />
    Comment on lines +5 to +7
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Presentation role conflicts with: has accessible name. The role will be ignored.

    Elements with role='presentation' or role='none' must not be focusable or have global ARIA attributes.

    Details

    When an element has role='presentation' or role='none', it's marked as decorative and removed from the accessibility tree. However, if the element is focusable or has certain ARIA attributes, the presentation role is ignored and the element remains accessible. This creates confusion. Either remove the presentation role, or remove the focusability/ARIA attributes.

    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: aria-label and aria-labelledby are prohibited on role "presentation".

    </div>
    );
    }
    12 changes: 12 additions & 0 deletions src/components/AriaRequired.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    // accesslint-057: ARIA Required Attr — missing required attributes
    export default function AriaRequired() {
    return (
    <div>
    <div role="checkbox">Accept terms</div>
    <div role="slider">Volume</div>
    <div role="combobox">Select option</div>
    Comment on lines +6 to +7
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    Form elements must have labels. Use , aria-label, or aria-labelledby.

    Details

    role: slider

    Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.

    <div role="scrollbar">Scroll</div>
    Comment on lines +5 to +8
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Role "checkbox" requires attribute "aria-checked".

    Elements with ARIA roles must have all required ARIA attributes.

    Details

    Some ARIA roles require specific attributes to function correctly. For example, checkbox requires aria-checked, slider requires aria-valuenow, heading requires aria-level. Without these attributes, assistive technologies cannot convey the element's state or value to users. Add the missing required attribute with an appropriate value.

    <div role="separator" tabIndex="0">---</div>
    </div>
    );
    }
    12 changes: 12 additions & 0 deletions src/components/AriaRoles.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    // accesslint-054: ARIA Roles — invalid role values
    // accesslint-059: ARIA Allowed Role — inappropriate roles for elements
    export default function AriaRoles() {
    return (
    <div>
    <div role="buttn">Click me</div>
    <div role="chckbox">Option A</div>
    <span role="headin" aria-level="2">Title</span>
    Comment on lines +6 to +8
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Invalid ARIA role "buttn".

    ARIA role values must be valid.

    Details

    Invalid role values are ignored by assistive technologies, meaning the element will not have the intended semantics. Check the spelling and use only roles defined in the WAI-ARIA specification. Common roles include: button, link, navigation, main, dialog, alert, tab, tabpanel, menu, menuitem.

    <p role="checkbox">I agree to terms</p>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Role "checkbox" requires attribute "aria-checked".

    Elements with ARIA roles must have all required ARIA attributes.

    Details

    Some ARIA roles require specific attributes to function correctly. For example, checkbox requires aria-checked, slider requires aria-valuenow, heading requires aria-level. Without these attributes, assistive technologies cannot convey the element's state or value to users. Add the missing required attribute with an appropriate value.

    </div>
    );
    }
    12 changes: 12 additions & 0 deletions src/components/AriaToggleFields.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    // accesslint-066: ARIA Toggle Field Name — toggle fields without names
    export default function AriaToggleFields() {
    return (
    <div>
    <div role="checkbox" aria-checked="false"></div>
    <div role="switch" aria-checked="true"></div>
    <div role="radio" aria-checked="false"></div>
    <div role="menuitemcheckbox" aria-checked="false"></div>
    <div role="menuitemradio" aria-checked="false"></div>
    Comment on lines +5 to +9
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    Form elements must have labels. Use , aria-label, or aria-labelledby.

    Details

    role: checkbox

    Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.


    WCAG 4.1.2: ARIA toggle field has no accessible name.

    ARIA toggle fields must have an accessible name.

    Details

    ARIA toggle controls (checkbox, switch, radio, menuitemcheckbox, menuitemradio) must have accessible names so users understand what option they're selecting. Add visible text content, aria-label, or use aria-labelledby to reference a visible label.

    Comment on lines +8 to +9
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1: Role "menuitemcheckbox" must be contained within: menu, menubar, group.

    Certain ARIA roles must be contained within specific parent roles.

    Details

    Some ARIA roles represent items that must exist within specific container roles. For example, a listitem must be within a list, a tab must be within a tablist. Wrap the element in the appropriate parent, or use native HTML elements that provide this structure (e.g.,

  • inside
      ).

  • </div>
    );
    }
    12 changes: 12 additions & 0 deletions src/components/AudioPlayer.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    // accesslint-091: Audio Captions — audio without text alternatives
    export default function AudioPlayer() {
    return (
    <div>
    <audio src="/podcast-ep1.mp3" controls></audio>
    <audio controls>
    <source src="/podcast-ep2.ogg" type="audio/ogg" />
    <source src="/podcast-ep2.mp3" type="audio/mpeg" />
    </audio>
    </div>
    );
    }
    13 changes: 13 additions & 0 deletions src/components/Breadcrumbs.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    // accesslint-077: Link Name — empty breadcrumb separator links
    // accesslint-011: Image Alt — separator images without alt
    export default function Breadcrumbs() {
    return (
    <nav>
    <a href="/"><img src="/home-icon.svg" /></a>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 2.4.4, WCAG 4.1.2: Link has no discernible text.

    Links must have discernible text via content, aria-label, or aria-labelledby.

    Details

    href: /
    Parent text: Products

      Widgets
    

    Screen reader users need to know where a link goes. Add descriptive text content, aria-label, or use aria-labelledby. For image links, ensure the image has alt text describing the link destination. Avoid generic text like 'click here' or 'read more'—link text should make sense out of context.

    <img src="/chevron.svg" />
    Comment on lines +6 to +7
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    Images must have alternate text. Add an alt attribute to elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.

    Details

    Link href: /

    Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.

    <a href="/products">Products</a>
    <img src="/chevron.svg" />
    <a href="/products/widgets">Widgets</a>
    </nav>
    );
    }
    23 changes: 23 additions & 0 deletions src/components/CardGrid.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    // accesslint-011: Image Alt — card images missing alt
    // accesslint-077: Link Name — empty links
    export default function CardGrid() {
    return (
    <div>
    <div className="card">
    <a href="/product/1"><img src="/product-1.jpg" /></a>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    Images must have alternate text. Add an alt attribute to elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.

    Details

    Link href: /product/1

    Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.


    WCAG 2.4.4, WCAG 4.1.2: Link has no discernible text.

    Links must have discernible text via content, aria-label, or aria-labelledby.

    Details

    href: /product/1
    Parent text: Product One
    Description of product one.

    Screen reader users need to know where a link goes. Add descriptive text content, aria-label, or use aria-labelledby. For image links, ensure the image has alt text describing the link destination. Avoid generic text like 'click here' or 'read more'—link text should make sense out of context.

    <h3>Product One</h3>
    <p>Description of product one.</p>
    </div>
    <div className="card">
    <a href="/product/2"><img src="/product-2.jpg" /></a>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.


    WCAG 2.4.4, WCAG 4.1.2: Link has no discernible text.

    <h3>Product Two</h3>
    <p>Description of product two.</p>
    </div>
    <div className="card">
    <a href="/product/3"><img src="/product-3.jpg" /></a>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.


    WCAG 2.4.4, WCAG 4.1.2: Link has no discernible text.

    <h3>Product Three</h3>
    <p>Description of product three.</p>
    </div>
    </div>
    );
    }
    15 changes: 15 additions & 0 deletions src/components/Carousel.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    // accesslint-011: Image Alt — carousel images without alt
    // accesslint-075: Button Name — prev/next buttons without text
    export default function Carousel() {
    return (
    <div>
    <button><img src="/arrow-left.svg" /></button>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    Images must have alternate text. Add an alt attribute to elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.

    Details

    Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.


    WCAG 4.1.2: Button has no discernible text.

    Buttons must have discernible text.

    Details

    Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.

    <div>
    <img src="/slide-1.jpg" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    <img src="/slide-2.jpg" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    <img src="/slide-3.jpg" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    </div>
    <button><img src="/arrow-right.svg" /></button>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    </div>
    );
    }
    20 changes: 20 additions & 0 deletions src/components/ContactForm.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    // accesslint-020: Form Label — inputs missing labels
    export default function ContactForm() {
    return (
    <form>
    <div>
    <input type="text" placeholder="Your name" />
    </div>
    <div>
    <input type="email" placeholder="Email address" />
    </div>
    <div>
    <input type="tel" placeholder="Phone number" />
    </div>
    <div>
    <textarea placeholder="Message"></textarea>
    </div>
    <button type="submit">Send</button>
    </form>
    );
    }
    30 changes: 30 additions & 0 deletions src/components/DataTable.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    // accesslint-088: Empty Table Header — table headers with no text
    // accesslint-084: Table Headers Attr — invalid header references
    export default function DataTable() {
    return (
    <table>
    <thead>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Best Practice: Table header cell is empty. Add text or use aria-label.

    Table header cells should have visible text.

    Details

    Empty table headers provide no information to screen reader users. Either add descriptive text to the header, or if the header is intentionally empty (like a corner cell), consider using a td element instead or adding a visually hidden label.

    <tr>
    <th></th>
    <th>Name</th>
    <th></th>
    <th>Email</th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td headers="nonexistent">1</td>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1: Headers attribute references non-existent ID "nonexistent".

    All cells in a table using headers attribute must reference valid header IDs.

    Details

    The headers attribute on table cells must reference IDs of header cells (th or td) within the same table. This creates explicit associations for screen readers. Verify all referenced IDs exist and spell them correctly. For simple tables, consider using scope on th elements instead.

    <td>Alice</td>
    <td>Admin</td>
    <td>alice@example.com</td>
    </tr>
    <tr>
    <td headers="also-missing">2</td>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1: Headers attribute references non-existent ID "nonexistent".

    <td>Bob</td>
    <td>User</td>
    <td>bob@example.com</td>
    </tr>
    </tbody>
    </table>
    );
    }
    19 changes: 19 additions & 0 deletions src/components/DefinitionListErrors.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    // accesslint-048: Definition List Item — dt/dd outside dl
    // accesslint-049: Definition List — dl with invalid children
    export default function DefinitionListErrors() {
    return (
    <div>
    <dl>
    <dt>Term 1</dt>
    <dd>Definition 1</dd>
    Comment on lines +7 to +8
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1:

    is not contained in a
    .

    and
    elements must be contained in a
    .
    Details

    Definition terms (

    ) and definitions (
    ) only have semantic meaning inside a definition list (
    ). Outside of
    , they're treated as generic text. Wrap related
    and
    pairs in a
    element to convey the term/definition relationship to assistive technologies.

    <p>Invalid child of dl</p>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.3.1:

    contains invalid child

    .

    elements must only contain
    ,
    ,
    , <script>, or .
    Details

    Definition lists have strict content requirements. Only

    (terms),
    (definitions), and
    (for grouping dt/dd pairs) are valid children. Other elements break the list structure for screen readers. Move invalid elements outside the
    , or restructure using proper definition list markup.

    <div>
    <dt>Term 2</dt>
    <dd>Definition 2</dd>
    </div>
    </dl>
    <dt>Orphaned term</dt>
    <dd>Orphaned definition</dd>
    </div>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/DeprecatedElements.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-009: Blink Element — blink must not be used
    // accesslint-010: Marquee Element — marquee must not be used
    export default function DeprecatedElements() {
    return (
    <div>
    <blink>This text blinks!</blink>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 2.2.2: The element causes accessibility issues. Remove it entirely.

    The element must not be used.

    Details

    Blinking content can cause seizures in users with photosensitive epilepsy and is distracting for users with attention disorders. The element is deprecated and should never be used. If you need to draw attention to content, use less intrusive methods like color, borders, or icons.

    <marquee>Scrolling announcement text</marquee>
    <marquee direction="right">More scrolling text</marquee>
    Comment on lines +7 to +8
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 2.2.2: The element causes accessibility issues. Replace with static content.

    The element must not be used.

    Details

    Scrolling or moving content is difficult for many users to read, especially those with cognitive or visual disabilities. The element is deprecated. Replace scrolling text with static content. If content must scroll, provide pause/stop controls and ensure it stops after 5 seconds.

    </div>
    );
    }
    14 changes: 14 additions & 0 deletions src/components/DuplicateAriaIds.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    // accesslint-089: Duplicate ID ARIA — duplicate IDs used in ARIA references
    export default function DuplicateAriaIds() {
    return (
    <div>
    <div id="desc1">First description</div>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Duplicate ID "desc1" referenced by aria-describedby.

    IDs used in ARIA and label associations must be unique to avoid broken references.

    Details

    First element:

    First description

    Referenced by: aria-describedby

    When aria-labelledby, aria-describedby, aria-controls, or label[for] reference a duplicate ID, only the first matching element is used. This breaks the intended relationship and may leave controls unnamed or descriptions missing. Ensure IDs referenced by ARIA attributes and label associations are unique throughout the document.

    <div id="desc1">Duplicate description</div>
    <input type="text" aria-describedby="desc1" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    Form elements must have labels. Use , aria-label, or aria-labelledby.

    Details

    type: text

    Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.


    <div id="label1">Label text</div>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Duplicate ID "desc1" referenced by aria-describedby.

    <div id="label1">Duplicate label text</div>
    <input type="text" aria-labelledby="label1" />
    </div>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/EmptyButtons.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-075: Button Name — buttons with no discernible text
    export default function EmptyButtons() {
    return (
    <div>
    <button></button>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Button has no discernible text.

    Buttons must have discernible text.

    Details

    Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.

    <button><img src="/icon-edit.svg" /></button>
    <button><img src="/icon-delete.svg" /></button>
    Comment on lines +6 to +7
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    Images must have alternate text. Add an alt attribute to elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.

    Details

    Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.

    <button><i className="fa fa-cog"></i></button>
    </div>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/EmptyHeadings.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-034: Empty Heading — headings with no text
    export default function EmptyHeadings() {
    return (
    <section>
    <h2></h2>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Best Practice: Heading is empty. Add text content or remove the heading element.

    Headings must have discernible text.

    Details

    Following content: "This section has an empty heading above."

    Screen reader users navigate pages by headings, so empty headings create confusing navigation points. Ensure all headings contain visible text or accessible names. If a heading is used purely for visual styling, use CSS instead of heading elements.

    <p>This section has an empty heading above.</p>
    <h3> </h3>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Best Practice: Heading is empty. Add text content or remove the heading element.

    <p>This heading has only whitespace.</p>
    </section>
    );
    }
    11 changes: 11 additions & 0 deletions src/components/FileUpload.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // accesslint-020: Form Label — file input without label
    // accesslint-075: Button Name — upload button with only icon
    export default function FileUpload() {
    return (
    <div>
    <input type="file" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    Form elements must have labels. Use , aria-label, or aria-labelledby.

    Details

    type: file

    Every form input needs an accessible label so users understand what information to enter. Use a element with a for attribute matching the input's id, wrap the input in a , or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.

    <button><img src="/upload.svg" /></button>
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 1.1.1: Image element missing alt attribute.

    Images must have alternate text. Add an alt attribute to elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.

    Details

    Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.


    WCAG 4.1.2: Button has no discernible text.

    Buttons must have discernible text.

    Details

    Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.

    <input type="file" accept="image/*" />
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    WCAG 4.1.2: Form element has no accessible label.

    </div>
    );
    }
    Loading