Skip to content

Add focus trap functionality to modal component #367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 17, 2025

Conversation

wazeerc
Copy link
Contributor

@wazeerc wazeerc commented Apr 16, 2025

Why?

According to Focus Order (Level A) from WCAG 2.2 - A web page implements modal dialogs via scripting. When the trigger button is activated, a dialog opens and focus is set within the dialog. As long as the dialog is open, focus is limited to the elements of the dialog. When the dialog is dismissed, focus returns to the button or the element following the button.

Summary by CodeRabbit

  • New Features
    • Introduced a focus trap option for modals to enhance accessibility by keeping keyboard focus within the modal when enabled.
    • Added new modal positioning options and support for extra small (xs) and small (sm) modal sizes.
  • Documentation
    • Updated modal documentation with details and examples for the new focus trap feature, additional size and position options, and changes to default prop values.
  • Chores
    • Added a new dependency to support the focus trap functionality.

Copy link
Contributor

coderabbitai bot commented Apr 16, 2025

Walkthrough

The changes introduce a "Focus Trap" feature to the modal component, enhancing accessibility by keeping keyboard focus within the modal when enabled. This is achieved by adding a new focusTrap boolean prop to the modal component and integrating the useFocusTrap composable from @vueuse/integrations. Documentation is updated to explain and demonstrate the feature, including a new example component. Additional modal API changes include new size options, a position prop, and a change in the default value for the persistent prop. The @vueuse/integrations dependency is added to the project.

Changes

File(s) Change Summary
docs/components/modal.md Updated documentation to describe the new focusTrap prop, added a section and example for focus trapping, expanded API props table.
docs/components/modal/examples/FwbModalExample.vue Added the focusTrap prop to the modal example, defaulting to false and passed down to the modal component.
docs/components/modal/examples/FwbModalExampleFocusTrap.vue Added a new example component demonstrating modals with and without focus trapping enabled.
src/components/FwbModal/FwbModal.vue Added the focusTrap prop, integrated useFocusTrap for keyboard focus management, updated mount/unmount logic for focus trapping.
package.json Added @vueuse/integrations as a new dependency.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ModalComponent
    participant useFocusTrap

    User->>ModalComponent: Open modal (with focusTrap=true)
    ModalComponent->>useFocusTrap: Initialize and activate focus trap
    useFocusTrap-->>ModalComponent: Focus is restricted within modal
    User->>ModalComponent: Interacts with modal (keyboard navigation)
    ModalComponent->>useFocusTrap: Deactivate focus trap on close
    useFocusTrap-->>ModalComponent: Focus trap removed
Loading

Poem

In the warren of code, a modal appears,
Now with a focus trap, it calms all our fears.
Keyboard hops stay safe inside,
While rabbits and users both enjoy the ride.
With new docs and examples, the feature is clear—
Accessibility blooms, let's all give a cheer!
🐇✨

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

netlify bot commented Apr 16, 2025

Deploy Preview for sensational-seahorse-8635f8 ready!

Name Link
🔨 Latest commit dbbe2f7
🔍 Latest deploy log https://app.netlify.com/sites/sensational-seahorse-8635f8/deploys/67ffee0779469f0008e97cdf
😎 Deploy Preview https://deploy-preview-367--sensational-seahorse-8635f8.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@wazeerc
Copy link
Contributor Author

wazeerc commented Apr 16, 2025

@CodeRabbit

Copy link
Contributor

coderabbitai bot commented Apr 16, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get PR information
gh pr view 367 --json title,body,state,author,additions,deletions

# Get a brief overview of what files were changed in this PR
gh pr view 367 --json files --jq '.files[].path' | head -10

# Get the branch name of the PR
gh pr view 367 --json headRefName

Length of output: 1109


🏁 Script executed:

#!/bin/bash
# Let's examine the FwbModal component implementation
cat src/components/FwbModal/FwbModal.vue

# Check the documentation for the modal component
cat docs/components/modal.md

# Look at the focus trap example
cat docs/components/modal/examples/FwbModalExampleFocusTrap.vue

Length of output: 11676


@wazeerc Hi there! I see you've pinged me in your PR about adding focus trap functionality to the modal component.

Based on what I can see, you've implemented:

  • A new focusTrap prop for the FwbModal component (default: false)
  • Focus management using useFocusTrap from @vueuse/integrations
  • Updated documentation with a new "Focus Trap" section
  • Added an example showing modals with and without focus trap

This is a great accessibility improvement that helps with WCAG 2.2 compliance for focus order (Level A).

How can I help you with this PR? I can:

  • Review the implementation in more detail
  • Suggest additional improvements
  • Answer any questions about the code
  • Help with testing strategies

Let me know what you need!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
docs/components/modal.md (1)

180-180: Remove trailing colon from heading for markdown style compliance.

The heading "### Props:" has a trailing colon, which is flagged by markdownlint (MD026). Remove the colon for consistency with markdown style guidelines.

-### Props:
+### Props
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

180-180: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cf7c5c and dbbe2f7.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • docs/components/modal.md (2 hunks)
  • docs/components/modal/examples/FwbModalExample.vue (3 hunks)
  • docs/components/modal/examples/FwbModalExampleFocusTrap.vue (1 hunks)
  • package.json (1 hunks)
  • src/components/FwbModal/FwbModal.vue (3 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/components/modal.md

180-180: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (16)
package.json (1)

72-72: Appropriate dependency added for focus trap functionality.

The addition of @vueuse/integrations at version ^13.1.0 is necessary to support the focus trap functionality through the useFocusTrap composable.

docs/components/modal/examples/FwbModalExample.vue (3)

12-12: LGTM: Modal example properly integrates the focus trap prop.

The focus-trap prop is correctly passed to the FwbModal component to enable accessibility functionality.


60-60: LGTM: Interface properly updated with focusTrap prop.

The ModalProps interface is correctly extended with the optional boolean property for focus trap functionality.


69-69: LGTM: Default value correctly configured.

Setting the default value of focusTrap to false makes the property opt-in, which is appropriate since it's a new feature that changes behavior.

docs/components/modal/examples/FwbModalExampleFocusTrap.vue (1)

1-15: LGTM: Excellent example demonstrating focus trap functionality.

This example component effectively demonstrates the difference between modals with and without focus trap by placing them side-by-side with appropriate trigger text labels. This makes it clear to users how the feature works and when to use it.

src/components/FwbModal/FwbModal.vue (8)

65-66: LGTM: Imports properly updated for focus trap functionality.

The component correctly imports the useFocusTrap composable from @vueuse/integrations and adds nextTick and lifecycle hooks needed for the implementation.


75-75: LGTM: Interface properly updated with focusTrap prop.

The optional boolean property for focus trap functionality is correctly added to the component's props interface.


83-83: LGTM: Default value correctly configured.

Setting the default value of focusTrap to false makes the property opt-in, which is appropriate for a new accessibility feature that changes keyboard behavior.


127-131: LGTM: Focus trap implementation looks good.

The focus trap is properly initialized with appropriate options:

  • Using the modal reference as the trapped element
  • Setting immediate: false to allow manual activation
  • Smart initial focus targeting the close button if available, otherwise the modal itself

This implementation aligns with accessibility best practices.


133-140: LGTM: Focus trap activation implemented correctly.

The focus trap is properly activated after the next tick (allowing the DOM to fully render) when the focusTrap prop is enabled. This conditional activation ensures the feature is only applied when requested.


142-144: LGTM: Cleanup handled properly.

The focus trap is correctly deactivated in the onBeforeUnmount lifecycle hook, ensuring that keyboard focus is properly released when the modal is closed.


101-111: Additional modal positioning options enhance flexibility.

The modal positioning options have been expanded with a comprehensive set of placement variations (top/center/bottom combined with start/center/end), which enhances the component's flexibility.


87-99: Modal size options have been expanded.

The modal size classes now include additional options like xs and sm, providing more granular control over the modal's width.

docs/components/modal.md (3)

7-7: Import for focus trap example is correct.

The new import for FwbModalExampleFocusTrap is appropriate and matches the new documentation section.


162-177: Focus Trap documentation is clear and accurate.

The new section effectively explains the feature, its accessibility benefits, and provides a clear usage example. No improvements needed.


182-188: API table updates are accurate and comprehensive.

The new and updated props are clearly documented, matching the implementation and PR objectives.

@Sqrcz Sqrcz self-assigned this Apr 16, 2025
@Sqrcz Sqrcz added the 🔧 enhancement New feature or request label Apr 16, 2025
@Sqrcz Sqrcz merged commit 31ffaaf into themesberg:main Apr 17, 2025
14 checks passed
@wazeerc wazeerc deleted the feature/modal-focustrap branch April 17, 2025 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔧 enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants