Skip to content
Merged
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
29 changes: 0 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,6 @@
> Looking for a nuxt version?
> [Nuxt version (Special thanks to BayBreezy)](https://github.com/BayBreezy/nuxt-tour)

> [!CAUTION]
> As of version 2.0.1, VueJS Tour has been rewritten in TypeScript. The `VTour` component is now a named export and must be imported as such.
> Please refer to the [Documentation](https://globalhive.github.io/vuejs-tour/) for more information on how to use VueJS Tour.

<br><br><br><br>
<ins>If you still want to use the old version, then this is the correct way to install it:</ins>

* Step 1: Go to your project directory and install VueJS Tour using npm:

```bash
cd my-project
npm install @globalhive/vuejs-tour
```

* Step 2: Import the plugin in your application entry point (typically `main.js`):

```javascript
import { createApp } from "vue";
import App from "./App.vue";
import VueJsTour from '@globalhive/vuejs-tour';
import '@globalhive/vuejs-tour/dist/style.css';

const app = createApp(App)
.use(VueJsTour)
.mount("#app");
```
Everything is ready! Now you can use VueJS Tour in your application.<br>
Make sure to check out the [documentation](https://globalhive.github.io/vuejs-tour/) for more information.

## Create a tour

Add the VueJS Tour component anywhere in your app. It is recommended to add it to `App.vue`
Expand Down
4 changes: 3 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default defineConfig({
nav: [
{ text: 'Guide', link: '/guide/what-is-vuejs-tour' },
{
text: '2.4.3',
text: '2.5.0',
items: [
{
text: 'Changelog',
Expand Down Expand Up @@ -98,6 +98,8 @@ export default defineConfig({
{ text: 'Skipping a Tour', link: '/guide/skipping-a-tour' },
{ text: 'Button Labels', link: '/guide/button-labels' },
{ text: 'Multiple Tours', link: '/guide/multiple-tours' },
{ text: 'Jump Options', link: '/guide/jump-options' },
{ text: 'Accessibility', link: '/guide/accessibility' },
{
text: 'Styling',
items: [
Expand Down
297 changes: 297 additions & 0 deletions docs/guide/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
# Accessibility Guide for VueJS Tour

## Current State

VueJS Tour now includes comprehensive WCAG 2.1 AA accessibility features, including keyboard navigation, ARIA attributes, focus management, and screen reader support.

**⚠️ Note:** Accessibility features are **disabled by default** (as of v2.5.0) pending further testing and validation. Enable them by setting `enableA11y: true` on the component.

## Implemented Accessibility Features

### 1. **ARIA Attributes** ✅

Implemented:

- ✅ `aria-label` on tooltip (configurable via `ariaLabel` prop or per-step `ariaLabel`)
- ✅ `aria-describedby` for step content
- ✅ `aria-live="polite"` region for step announcements
- ✅ `aria-modal="true"` when `enableA11y` is enabled
- ✅ `role="dialog"` for proper semantic structure
- ✅ Enhanced `aria-label` attributes on all buttons

### 2. **Keyboard Navigation** ✅

Implemented:

- ✅ `Escape` key to close tour
- ✅ `ArrowRight` or `Enter` to go to next step
- ✅ `ArrowLeft` to go to previous step
- ✅ Keyboard navigation can be disabled via `keyboardNav: false`
- ⚠️ Focus trap not yet implemented (planned for future release)

### 3. **Focus Management** ✅

Implemented:

- ✅ Tooltip receives focus when opened (when `enableA11y` is true)
- ✅ Previous focus restored when tour ends
- ✅ `tabindex="0"` on tooltip for keyboard accessibility

### 4. **Screen Reader Support** ✅

Implemented:

- ✅ Step progress announced ("Step 2 of 5")
- ✅ Descriptive button labels with step context
- ✅ Content changes announced via aria-live region
- ✅ Screen reader only content via `.vjt-sr-only` CSS class

### 5. **Semantic Structure** ✅

Implemented:

- ✅ `role="dialog"` on tooltip (changed from `role="tooltip"` for better modal semantics)
- ✅ Step counter announced to screen readers
- ✅ Proper ARIA attributes on all interactive elements

## Usage

### Enabling Accessibility Features

Accessibility features are disabled by default. To enable them:

```vue
<VTour
:steps="steps"
:enableA11y="true"
:keyboardNav="true"
ariaLabel="Product tour"
/>
```

### Available Props

```typescript
interface VTourProps {
// ... other props

/** Enable accessibility features (default: false) */
readonly enableA11y?: boolean;

/** Enable keyboard navigation (default: true, only active when enableA11y is true) */
readonly keyboardNav?: boolean;

/** Custom aria-label for the tour (default: "Guided tour") */
readonly ariaLabel?: string;
}

interface ITourStep {
// ... other props

/** Descriptive label for screen readers */
readonly ariaLabel?: string;
}
```

### Example: Per-Step Accessibility Labels

```vue
<script setup>
const steps = [
{
target: '#welcome',
content: 'Welcome to our app!',
ariaLabel: 'Welcome step: Introduction to the application',
},
{
target: '#profile',
content: 'View your profile here',
ariaLabel: 'Profile step: Learn about your user profile',
},
];
</script>

<template>
<VTour :steps="steps" :enableA11y="true" />
</template>
```

## Implementation Details

### Features Already Implemented ✅

1. **ARIA Live Region** - Announces step changes to screen readers

```vue
<div
v-if="enableA11y"
role="status"
aria-live="polite"
aria-atomic="true"
class="vjt-sr-only"
>
Step {{ currentStepIndex + 1 }} of {{ props.steps.length }}
</div>
```

2. **Enhanced Tooltip Semantics** - Proper dialog role and ARIA attributes

```vue
<div
:id="tooltipId"
role="dialog"
:aria-modal="enableA11y ? 'true' : undefined"
:aria-label="getCurrentStep?.ariaLabel || ariaLabel"
:aria-describedby="`${tooltipId}-content`"
:tabindex="enableA11y ? '0' : undefined"
/>
```

3. **Keyboard Navigation** - Arrow keys, Enter, and Escape support

```typescript
const onKeydown = (event: KeyboardEvent): void => {
if (!tourVisible.value || !props.enableA11y || !props.keyboardNav) return;

switch (event.key) {
case 'Escape':
endTour();
event.preventDefault();
break;
case 'ArrowRight':
case 'Enter':
nextStep();
event.preventDefault();
break;
case 'ArrowLeft':
if (currentStepIndex.value > 0) {
lastStep();
event.preventDefault();
}
break;
}
};
```

4. **Focus Management** - Stores and restores focus

```typescript
let previousFocus: HTMLElement | null = null;

const startTour = async () => {
if (props.enableA11y && typeof document !== 'undefined') {
previousFocus = document.activeElement as HTMLElement;
}
// ... tour starts
if (props.enableA11y) {
await nextTick();
_Tooltip.value?.focus();
}
};

const stopTour = () => {
if (props.enableA11y && previousFocus) {
previousFocus.focus();
previousFocus = null;
}
};
```

5. **Enhanced Button Labels** - Descriptive aria-labels for all actions

```vue
<button
type="button"
@click.prevent="nextStep"
:aria-label="
enableA11y
? isLastStep
? 'Finish tour'
: `Go to next step, step ${nextStepIndex + 1} of ${props.steps.length}`
: undefined
"
>
{{ getNextLabel }}
</button>
```

### Future Enhancements ⚠️

These features are planned for future releases:

1. **Focus Trap** - Trap focus within modal when backdrop is active
2. **Customizable Keyboard Shortcuts** - Allow users to configure key bindings
3. **Visual Progress Indicators** - Show step progress visually
4. **Skip to Content** - Quick navigation option

## Backward Compatibility

All accessibility features:

- ⚠️ Default to **disabled** (`enableA11y: false`) as of v2.4.3 pending further testing
- Are opt-in via `enableA11y: true` prop
- Do not break existing implementations when disabled
- Add ~3KB to bundle size (minimal impact)

## Testing Requirements

1. **Keyboard-only navigation**
- Can navigate all steps without mouse
- Can dismiss tour with Escape
- Focus visible at all times

2. **Screen reader testing**
- NVDA (Windows)
- JAWS (Windows)
- VoiceOver (macOS/iOS)
- TalkBack (Android)

3. **Automated testing**
- axe-core integration
- ARIA validity checks
- Keyboard interaction tests

## Resources

- [WAI-ARIA Authoring Practices Guide - Dialog](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)
- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)
- [focus-trap library](https://github.com/focus-trap/focus-trap)
- [Vue A11y Best Practices](https://vue-a11y.com/)

## Testing Status

**Implemented (v2.4.3):** ✅

- ✅ Keyboard navigation tests (28 test cases)
- ✅ ARIA attributes validation
- ✅ Focus management tests
- ✅ Screen reader announcement tests

**Pending:**

1. **Manual testing with screen readers**
- NVDA (Windows)
- JAWS (Windows)
- VoiceOver (macOS/iOS)
- TalkBack (Android)

2. **Real-world validation**
- User testing with keyboard-only users
- Screen reader user feedback
- Production environment testing

3. **Automated accessibility testing**
- axe-core integration
- Lighthouse accessibility audits
- pa11y or similar tools

## Status

✅ **Phase 1 (Critical) features implemented** - All essential WCAG AA compliance features are in place and tested. Features are disabled by default pending further validation.

**Next steps:**

1. Community testing and feedback
2. Screen reader validation
3. Enable by default once vetted
4. Implement Phase 2 features (focus trap, custom shortcuts)
Loading
Loading