Loading...
Loading...
Analyzes code for WCAG 2.4.4 Link Purpose (In Context) compliance. Identifies generic link text, ambiguous links, and links without sufficient context. Recommends descriptive link text and proper ARIA attributes.
npx skill4agent add accesslint/claude-marketplace link-purposearia-labelaria-labelledbyaria-describedbysr-only// VIOLATION - Generic "click here"
<p>
For more information about accessibility, <a href="/wcag">click here</a>.
</p>
// VIOLATION - Generic "read more"
<div className="article-card">
<h3>Understanding WCAG 2.4.4</h3>
<p>Links must have descriptive text...</p>
<a href="/article/1">Read more</a>
</div>
// COMPLIANT - Descriptive text
<p>
For more information, <a href="/wcag">read our WCAG compliance guide</a>.
</p>
// COMPLIANT - sr-only text for context
<div className="article-card">
<h3>Understanding WCAG 2.4.4</h3>
<p>Links must have descriptive text...</p>
<a href="/article/1">
Read more
<span className="sr-only">about Understanding WCAG 2.4.4</span>
</a>
</div>
// COMPLIANT - aria-label
<div className="article-card">
<h3 id="article-1-title">Understanding WCAG 2.4.4</h3>
<p>Links must have descriptive text...</p>
<a href="/article/1" aria-labelledby="read-more-1 article-1-title" id="read-more-1">
Read more
</a>
</div>
// BEST PRACTICE - Link the heading
<div className="article-card">
<h3>
<a href="/article/1">Understanding WCAG 2.4.4</a>
</h3>
<p>Links must have descriptive text...</p>
</div>click hereread morelearn moremoreherecontinuemore infodetailsaria-labelaria-labelledby// VIOLATION - Ambiguous repeated links
<div className="product-grid">
{products.map(product => (
<div key={product.id}>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<a href={`/products/${product.id}`}>Learn more</a>
</div>
))}
</div>
// COMPLIANT - Descriptive unique text
<div className="product-grid">
{products.map(product => (
<div key={product.id}>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<a href={`/products/${product.id}`}>
Learn more about {product.name}
</a>
</div>
))}
</div>
// COMPLIANT - sr-only text for uniqueness
<div className="product-grid">
{products.map(product => (
<div key={product.id}>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<a href={`/products/${product.id}`}>
Learn more
<span className="sr-only">about {product.name}</span>
</a>
</div>
))}
</div>
// COMPLIANT - Link the heading or image
<div className="product-grid">
{products.map(product => (
<div key={product.id}>
<a href={`/products/${product.id}`}>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
</a>
</div>
))}
</div><a><Link>// VIOLATION - Image link with no alt text
<a href="/profile">
<img src="/icons/user.svg" alt="" />
</a>
// VIOLATION - Icon link without label
<a href="/settings">
<SettingsIcon />
</a>
// COMPLIANT - Descriptive alt text
<a href="/profile">
<img src="/icons/user.svg" alt="User profile" />
</a>
// COMPLIANT - aria-label on link
<a href="/settings" aria-label="Settings">
<SettingsIcon aria-hidden="true" />
</a>
// COMPLIANT - Visually hidden text
<a href="/search">
<SearchIcon aria-hidden="true" />
<span className="sr-only">Search</span>
</a><a><img>alt// VIOLATION - Raw URL as link text
<p>
Visit our site at
<a href="https://example.com/very/long/path/to/accessibility/guide">
https://example.com/very/long/path/to/accessibility/guide
</a>
</p>
// COMPLIANT - Descriptive link text
<p>
Visit our <a href="https://example.com/very/long/path/to/accessibility/guide">
accessibility guide
</a>
</p>
// ACCEPTABLE - Short, meaningful URLs
<p>
Follow us on Twitter: <a href="https://twitter.com/example">twitter.com/example</a>
</p>// VIOLATION - Vague action
<button>
<a href="/form">Submit</a>
</button>
// VIOLATION - No context for what continues
<a href="/step2">Continue</a>
// COMPLIANT - Descriptive action
<a href="/form">Submit registration form</a>
// COMPLIANT - Context provided
<section aria-labelledby="checkout-heading">
<h2 id="checkout-heading">Review your order</h2>
<a href="/step2">Continue to payment</a>
</section>// VIOLATION - No file information
<a href="/docs/report.pdf">Download report</a>
// COMPLIANT - File type and size
<a href="/docs/report.pdf">
Download annual report (PDF, 2.3 MB)
</a>
// COMPLIANT - aria-label with details
<a
href="/docs/report.pdf"
aria-label="Download annual report, PDF format, 2.3 megabytes"
>
Download report
<span className="sr-only">(PDF, 2.3 MB)</span>
</a><a>href<Link><router-link><nuxt-link><button>onclickaria-labelaria-labelledbyaltfile:lineLink Purpose Analysis Report
Files analyzed: 3
Violations found: 7
- Generic link text: 4
- Ambiguous links: 2
- Image links without alt: 1
---
Violation #1: src/components/ArticleCard.tsx:23
Type: Generic Link Text
Issue: "Read more" link without additional context for screen readers
Current Code:
<a href={`/articles/${article.id}`}>Read more</a>
Recommendation (choose one approach):
Option 1 - Add sr-only text (maintains visual design):
<a href={`/articles/${article.id}`}>
Read more
<span className="sr-only">about {article.title}</span>
</a>
Option 2 - Use aria-label:
<a
href={`/articles/${article.id}`}
aria-label={`Read more about ${article.title}`}
>
Read more
</a>
Option 3 - Make link text descriptive (best practice):
<a href={`/articles/${article.id}`}>
Read the full article: {article.title}
</a>
Option 4 - Link the heading instead:
<h3>
<a href={`/articles/${article.id}`}>{article.title}</a>
</h3>
<p>{article.excerpt}</p>
WCAG: 2.4.4 Link Purpose (In Context) (Level A)
---
Violation #2: src/components/ProductGrid.tsx:45
Type: Ambiguous Links
Issue: Multiple "Learn more" links with identical text leading to different products. Screen reader users navigating the links list cannot distinguish between them.
Current Code:
{products.map(product => (
<a href={`/products/${product.id}`}>Learn more</a>
))}
Recommendation:
Include product name for uniqueness:
{products.map(product => (
<a href={`/products/${product.id}`}>
Learn more about {product.name}
</a>
))}
Or use sr-only text:
{products.map(product => (
<a href={`/products/${product.id}`}>
Learn more
<span className="sr-only">about {product.name}</span>
</a>
))}
Or link the entire card/heading:
{products.map(product => (
<a href={`/products/${product.id}`} className="product-card-link">
<img src={product.image} alt="" />
<h3>{product.name}</h3>
<p>{product.description}</p>
</a>
))}
WCAG: 2.4.4 Link Purpose (In Context) (Level A)
---
Violation #3: src/components/Navigation.tsx:12
Type: Image Link Without Alt Text
Issue: Icon-only link to settings page has no accessible name
Current Code:
<a href="/settings">
<SettingsIcon />
</a>
Recommendation:
Add aria-label to the link:
<a href="/settings" aria-label="Settings">
<SettingsIcon aria-hidden="true" />
</a>
Or add visually hidden text:
<a href="/settings">
<SettingsIcon aria-hidden="true" />
<span className="sr-only">Settings</span>
</a>
WCAG: 2.4.4 Link Purpose (In Context) (Level A)
---
Violation #4: src/pages/Resources.tsx:67
Type: Download Link Without File Information
Issue: Link doesn't indicate file type or size for download
Current Code:
<a href="/downloads/guide.pdf">Download accessibility guide</a>
Recommendation:
Include file format and size:
<a href="/downloads/guide.pdf">
Download accessibility guide (PDF, 1.5 MB)
</a>
Or use sr-only for file details:
<a href="/downloads/guide.pdf">
Download accessibility guide
<span className="sr-only"> (PDF format, 1.5 megabytes)</span>
</a>
WCAG: 2.4.4 Link Purpose (In Context) (Level A)// COMPLIANT - Context in same sentence
<p>
Learn more about <a href="/wcag-2.4.4">WCAG 2.4.4 Link Purpose requirements</a>
in our comprehensive guide.
</p>
// COMPLIANT - Context in same paragraph
<p>
Our accessibility guide covers all WCAG 2.1 Level A and AA requirements.
<a href="/guide">Read the guide</a> to learn best practices.
</p>// GOOD - Same text, same destination
<nav>
<a href="/home">Home</a>
</nav>
<footer>
<a href="/home">Home</a>
</footer>// COMPLIANT - Image is decorative, text provides purpose
<a href="/profile">
<img src="/avatar.jpg" alt="" />
View John's Profile
</a>// React Router
import { Link } from 'react-router-dom'
<Link to="/about">About Us</Link>
// Next.js
import Link from 'next/link'
<Link href="/about">About Us</Link>
// Common issue in card components
<Card>
<CardImage src={img} alt={title} />
<CardTitle>{title}</CardTitle>
<Link href={url}>Read more</Link> {/* VIOLATION */}
</Card><!-- Vue Router -->
<router-link to="/about">About Us</router-link>
<!-- Nuxt -->
<nuxt-link to="/about">About Us</nuxt-link>
<!-- Common issue in v-for -->
<div v-for="item in items" :key="item.id">
<a :href="item.url">Learn more</a> <!-- VIOLATION -->
</div>sr-onlyvisually-hiddenscreen-reader-onlyscreen-reader-textassistive-textsr-text/\b(click here|tap here|read more|learn more|more info|more|here|continue|next|details|view details|download|go|go to|link)\b/i/(https?:\/\/|www\.)[^\s<]+/<a><img><a><a>.map()v-for.pdf.doc.xls.ziparia-labelaria-labelledby