Accessibility (a11y) Strategy
Relevant source files
The following files were used as context for generating this wiki page:The accessibility strategy for this portfolio is centered on building a "Headless Accessibility" foundation. This approach ensures that the application is fully usable via keyboard and screen readers without sacrificing visual design freedom. The core of this strategy is the adoption of Radix UI primitives, which provide unstyled, accessible components that can be fully customized.
This commitment to accessibility is evident through navigational aids, thoughtful component implementation, and clear visual feedback for user interactions. The goal is to achieve 100% keyboard navigation and robust screen reader support, making the portfolio a resilient and inclusive digital experience.
Sources: README.md:31-32
Core Philosophy: Headless UI Primitives
The project's architecture relies on headless UI libraries, specifically Radix UI, to handle complex accessibility logic out of the box. By using Radix, the application inherits WAI-ARIA standards, focus management, and keyboard interactions for components like accordions and tooltips. This decouples the accessibility logic from the visual presentation.
The dependencies listed in package.json confirm the integration of several Radix components:
@radix-ui/react-accordion@radix-ui/react-tooltip@radix-ui/react-slot@radix-ui/react-aspect-ratio@radix-ui/react-context-menu@radix-ui/react-hover-card
Sources: README.md:31-32, package.json:15-22
The following diagram illustrates how a custom UI component is built upon a Radix primitive, separating concerns.
Navigational Aids
To enhance usability for all users, especially those relying on assistive technologies, the application implements several key navigational features.
"Skip to Main" Link
A "Skip to Main" button is provided to allow keyboard users to bypass the navigation header and jump directly to the main content of the page. This is a crucial feature for efficient navigation.
- Implementation: The button is present in the
Navbarcomponent. It is visually hidden by default and becomes visible only when it receives focus. - Functionality: On click, it finds the element with
id="main-content"and moves focus to it, scrolling it into view.
Sources: src/widgets/Navbar/Navbar.tsx:21-26, src/pages/Home.tsx:8
The flow for this interaction is as follows:
Here is the code snippet for the button:
// src/widgets/Navbar/Navbar.tsx:52-64
<div className="fixed top-4 left-4 z-100 pointer-events-auto">
<Button
variant="primary"
size="md"
onClick={handleSkipToMain}
icon={
<ArrowDown
size={16}
className="transition-transform duration-300 group-hover:translate-y-1"
/>
}
iconPosition="right"
className="opacity-0 focus:opacity-100 pointer-events-none focus:pointer-events-auto transition-all duration-200 -translate-y-[200%] focus:translate-y-0 shadow-xl"
tabIndex={0}
>
{homeContent.navbar.skipToMain}
</Button>
</div>
Semantic HTML and Landmarks
The application uses semantic HTML5 elements to define page structure and landmarks, which helps screen readers interpret the layout and purpose of different sections.
| Landmark/Element | Purpose | File Example |
|---|---|---|
<main> | The primary content of the page. | src/pages/Home.tsx:7 |
<nav> | Contains the main site navigation. | src/widgets/Navbar/Navbar.tsx:30 |
<footer> | Contains footer content like links and copyright. | src/widgets/Footer/Footer.tsx:21 |
<section> | Groups related content thematically. | src/pages/Home.tsx:12 |
<button> | Used for actions. | src/widgets/Footer/Footer.tsx:30 |
<a> | Used for hyperlinks. | src/widgets/Footer/Footer.tsx:70 |
Sources: src/pages/Home.tsx:7, src/widgets/Navbar/Navbar.tsx:30, src/widgets/Footer/Footer.tsx:21
Component-Level Accessibility
Interactive Elements with ARIA
Where standard HTML elements are not sufficient, ARIA (Accessible Rich Internet Applications) attributes are used to provide semantics.
aria-label: Icon-only buttons in theFooterusearia-labelto provide a descriptive text alternative for screen readers.role="button": Customdivelements in theHerosection that act as interactive cards are givenrole="button"to signify their function.tabIndex={0}: Non-native interactive elements, such as<span>and<div>wrappers for tooltips and cards, are made focusable usingtabIndex={0}.
// src/widgets/Footer/Footer.tsx:432-438
<a
href="https://github.com/BonyKoshy%22
target="_blank"
rel="noreferrer"
aria-label="GitHub"
className="..."
>
<SiGithub size={18} />
</a>
Sources: src/widgets/Footer/Footer.tsx:435, src/widgets/Hero/Hero.tsx:188, 209
Tooltip Accessibility
The custom Tooltip component is designed to be accessible across different input methods. It handles mouse, keyboard, and touch events to ensure all users can access the tooltip content.
- Mouse: Appears on
onMouseEnterand follows the cursor. - Touch: Appears on
onTouchStartand hides after a delay ononTouchEnd. - Keyboard: The trigger element is focusable via
tabIndex={0}, and the tooltip can be activated.
The sequence diagram below shows how the Tooltip component responds to user interactions.
Visual Accessibility
Focus Management
Clear and consistent focus indicators are essential for keyboard navigation. The application defines a global focus-visible style to ensure that any focusable element has a distinct outline when navigated to via keyboard.
This style applies a 2px solid outline using the primary theme color, making the currently focused element easy to identify.
/* src/app/index.css:251-255 */
:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
border-radius: 4px;
}
Sources: src/app/index.css:251-255
Theming and Contrast
The application includes a system-aware, persistent dark/light theming engine. While not explicitly a WCAG compliance feature without contrast ratio checks, providing theme choices can significantly improve readability and reduce eye strain for users with light sensitivity or those in different lighting conditions. The theme variables are defined in src/app/index.css.
Sources: src/app/index.css:8-67, README.md:33-34
Summary
The accessibility strategy for this project is robust and deeply integrated into its architecture. By leveraging Radix UI for a headless foundation, the application ensures that core components are accessible by default. This is supplemented by crucial navigational aids like a "Skip to Main" link and the correct use of semantic HTML. Furthermore, component-level implementations and global CSS for focus visibility demonstrate a thorough approach to creating an inclusive user experience that supports keyboard and screen reader users effectively.