Documentation is currently in beta. Report issues →
Design SystemAccessibility

Accessibility

Y3NKO is designed to meet WCAG 2.1 AA standards and provide a great experience for all users.

Core Requirements

Color Contrast

All text meets minimum contrast ratios:

Text TypeMinimum RatioOur Implementation
Normal text4.5:1Night on Paper: 15.8:1
Large text (18pt+)3:1Ghana Red on Paper: 5.2:1
UI components3:1Gold on Coffee: 6.3:1

Focus Indicators

All interactive elements have visible focus states:

*:focus-visible {
  outline: 2px solid var(--ghana-gold);
  outline-offset: 2px;
}

The Ghana Gold (#D4A853) provides high visibility on both light and dark backgrounds.

Touch Targets

Minimum touch target size is 44x44 pixels:

{/* Button with adequate size */}
<Button className="min-h-[44px] min-w-[44px]">
  {/* Content */}
</Button>
 
{/* Icon button */}
<button className="p-3">
  <Icon className="w-5 h-5" />
</button>

Keyboard Navigation

Tab Order

Ensure logical tab order follows visual layout:

{/* Good: natural reading order */}
<nav>
  <Link href="/">Home</Link>
  <Link href="/accommodations">Accommodations</Link>
  <Link href="/about">About</Link>
</nav>
 
{/* Avoid: tabindex manipulation */}
<nav>
  <Link href="/" tabIndex={3}>Home</Link> {/* Don't do this */}
</nav>

Keyboard Shortcuts

Interactive elements respond to expected keys:

ElementKeys
Links, buttonsEnter, Space
CheckboxesSpace
DropdownsArrow keys, Enter, Escape
ModalsEscape to close
CarouselsArrow keys

Allow users to skip to main content:

<a
  href="#main-content"
  className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-white focus:text-[#CE1126]"
>
  Skip to main content
</a>
 
<main id="main-content">
  {/* Page content */}
</main>

Screen Readers

Semantic HTML

Use appropriate HTML elements:

{/* Good: semantic structure */}
<header>
  <nav aria-label="Main navigation">
    <ul>
      <li><Link href="/">Home</Link></li>
    </ul>
  </nav>
</header>
<main>
  <article>
    <h1>Page Title</h1>
    <section aria-labelledby="section-heading">
      <h2 id="section-heading">Section</h2>
    </section>
  </article>
</main>
<footer>
  {/* Footer content */}
</footer>

ARIA Labels

Add labels to icon-only buttons:

{/* Icon button with label */}
<button aria-label="Add to favorites">
  <Heart className="w-5 h-5" />
</button>
 
{/* Close button */}
<button aria-label="Close dialog">
  <X className="w-5 h-5" />
</button>
 
{/* Search button */}
<button aria-label="Search accommodations">
  <Search className="w-5 h-5" />
</button>

Decorative Icons

Hide decorative icons from screen readers:

{/* Decorative icon next to text */}
<span className="flex items-center gap-2">
  <MapPin className="w-4 h-4" aria-hidden="true" />
  Accra, Ghana
</span>
 
{/* Informational icon */}
<span className="flex items-center gap-2">
  <Star className="w-4 h-4 fill-yellow-400 text-yellow-400" aria-hidden="true" />
  <span>4.8 rating</span>
</span>

Live Regions

Announce dynamic content changes:

{/* Toast notifications */}
<div role="alert" aria-live="polite">
  Booking confirmed!
</div>
 
{/* Error messages */}
<div role="alert" aria-live="assertive">
  Payment failed. Please try again.
</div>
 
{/* Loading status */}
<div aria-live="polite" aria-busy={isLoading}>
  {isLoading ? 'Loading...' : 'Content loaded'}
</div>

Images

Alt Text

Provide meaningful alt text:

{/* Informative image */}
<Image
  src="/villa.jpg"
  alt="Luxury beach villa with infinity pool overlooking the ocean"
/>
 
{/* Decorative image */}
<Image
  src="/pattern.svg"
  alt=""
  role="presentation"
/>
 
{/* User avatar */}
<Image
  src={user.avatar}
  alt={`${user.name}'s profile photo`}
/>

Complex Images

For complex images like charts, provide detailed descriptions:

<figure>
  <Image src="/booking-chart.png" alt="Monthly bookings chart" />
  <figcaption>
    Chart showing booking trends from January to December.
    Bookings peaked in July with 150 reservations.
  </figcaption>
</figure>

Forms

Labels

Every input needs an associated label:

{/* Explicit label */}
<div>
  <Label htmlFor="email">Email Address</Label>
  <Input id="email" type="email" />
</div>
 
{/* Implicit label */}
<label>
  Email Address
  <Input type="email" />
</label>

Error Messages

Associate errors with inputs:

<div>
  <Label htmlFor="email">Email</Label>
  <Input
    id="email"
    aria-invalid={!!errors.email}
    aria-describedby={errors.email ? "email-error" : undefined}
  />
  {errors.email && (
    <p id="email-error" role="alert" className="text-red-600 text-sm mt-1">
      {errors.email.message}
    </p>
  )}
</div>

Required Fields

Indicate required fields clearly:

<Label htmlFor="name">
  Full Name <span className="text-red-500" aria-hidden="true">*</span>
  <span className="sr-only">(required)</span>
</Label>

Reduced Motion

Respect user preferences:

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Or use Tailwind:

<div className="motion-safe:animate-fade-in motion-reduce:opacity-100">
  {/* Animates only if reduced motion not set */}
</div>

Testing Checklist

  • Navigate entire page using only keyboard
  • Test with screen reader (VoiceOver, NVDA)
  • Check color contrast with browser dev tools
  • Verify focus indicators are visible
  • Test with 200% zoom
  • Enable prefers-reduced-motion and verify
  • Test with prefers-color-scheme if dark mode supported
  • Validate HTML structure
  • Check heading hierarchy (h1 → h2 → h3)

Tools

  • axe DevTools: Browser extension for accessibility testing
  • WAVE: Web accessibility evaluation tool
  • Lighthouse: Chrome DevTools audit
  • VoiceOver: macOS built-in screen reader
  • NVDA: Free Windows screen reader