Skip to content

Render skip-to-main-content as <a href="#main-content"> instead of a button#5610

Draft
bram-atmire wants to merge 1 commit intoDSpace:mainfrom
bram-atmire:fix/5605-skip-link-anchor
Draft

Render skip-to-main-content as <a href="#main-content"> instead of a button#5610
bram-atmire wants to merge 1 commit intoDSpace:mainfrom
bram-atmire:fix/5605-skip-link-anchor

Conversation

@bram-atmire
Copy link
Copy Markdown
Member

References

Description

Render the skip-to-main-content control as <a href="#main-content"> instead of a <button>. Aligns with the canonical WAI-ARIA Authoring Practices skip-link pattern and removes the JS click-handler dependency.

Instructions for Reviewers

List of changes in this PR:

  • src/app/root/root.component.html - the skip control becomes <a href="#main-content" class="sr-only" id="skip-to-main-content">. Added tabindex="-1" to <main id="main-content"> so the fragment navigation reliably moves focus across browsers (without tabindex, some browsers do not move focus to non-form elements after fragment navigation).
  • src/app/root/root.component.ts - removed the now-unused skipToMainContent() method that previously focused #main-content programmatically.
  • src/app/root/root.component.spec.ts - added specs asserting (1) the skip link is an <a> with the correct href, and (2) the <main> target carries tabindex="-1".

How to test:

  1. Start the UI (yarn start or pm2 start config/dspace-ui-test.json).
  2. Reload a page and immediately press Tab. The "Skip to main content" link should slide into view (already styled by root.component.scss).
  3. Press Enter (no JS click handler is involved). The URL should gain #main-content and keyboard focus should land on the <main> element. A subsequent Tab should move focus to the first interactive element inside the page content rather than back to a navbar item.
  4. npm run test -- --include='src/app/root/root.component.spec.ts' shows 3 specs pass.

This is not fixing a current WCAG failure (the existing button works for any user who reaches the running SPA, since DSpace requires JS to render). It aligns the implementation with the canonical pattern - see #5605 for full rationale.

Checklist

  • My PR is created against the main branch of code (unless it is a backport or is fixing an issue specific to an older branch).
  • My PR is small in size (3 files, 19 insertions, 11 deletions).
  • My PR passes ESLint validation using npm run lint
  • My PR doesn't introduce circular dependencies (verified via npm run check-circ-deps)
  • My PR includes TypeDoc comments for all new (or modified) public methods and classes. (n/a - method removed, no new methods)
  • My PR passes all specs/tests and includes new/updated specs or tests based on the Code Testing Guide.
  • My PR aligns with Accessibility guidelines if it makes changes to the user interface.
  • My PR uses i18n (internationalization) keys instead of hardcoded English text, to allow for translations. (existing key root.skip-to-content retained)
  • My PR includes details on how to test it.
  • If my PR includes new libraries/dependencies (in package.json), I've made sure their licenses align with the DSpace BSD License based on the Licensing of Contributions documentation. (n/a)
  • If my PR includes new features or configurations, I've provided basic technical documentation in the PR itself. (n/a)
  • If my PR fixes an issue ticket, I've linked them together.

…button

The button worked in the running SPA via a JS click handler that focused
#main-content, but the canonical and most thoroughly assistive-tech-tested
skip-link pattern is a plain anchor. Anchors work without JavaScript, survive
hydration glitches, and need no custom focus handler.

Changes:
- root.component.html: replace <button (click)="skipToMainContent()"> with
  <a href="#main-content">. Add tabindex="-1" to <main id="main-content"> so
  the fragment navigation reliably moves focus across browsers.
- root.component.ts: drop the now-unused skipToMainContent() method.
- root.component.spec.ts: add specs verifying the anchor is rendered with the
  correct href and that the <main> target carries tabindex="-1".

References DSpace#5605
@lgeggleston lgeggleston added improvement accessibility 1 APPROVAL pull request only requires a single approval to merge labels May 4, 2026
@lgeggleston lgeggleston moved this to 🙋 Needs Reviewers Assigned in DSpace 10.0 Release May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1 APPROVAL pull request only requires a single approval to merge accessibility improvement

Projects

Status: 🙋 Needs Reviewers Assigned

Development

Successfully merging this pull request may close these issues.

Cleanup: use <a href="#main-content"> for the skip link to align with the canonical pattern

2 participants