Skip to content

♿️(frontend) use anchor links for interlinking sub-documents#2391

Open
Ovgodd wants to merge 2 commits into
mainfrom
fix/a11y-2344-subdocs-links-semantic
Open

♿️(frontend) use anchor links for interlinking sub-documents#2391
Ovgodd wants to merge 2 commits into
mainfrom
fix/a11y-2344-subdocs-links-semantic

Conversation

@Ovgodd
Copy link
Copy Markdown
Collaborator

@Ovgodd Ovgodd commented Jun 3, 2026

Purpose

Make sub-doc interlinks accessible by using real <a href> links instead of invalid <span type="button"> markup.

Proposal

  • Render interlinks as <a href> in LinkSelected.tsx
  • Add :focus-visible outline for keyboard users

@Ovgodd Ovgodd added bug Something isn't working accessibility triage labels Jun 3, 2026
@Ovgodd Ovgodd self-assigned this Jun 3, 2026
Render sub-doc interlinks as a tag> instead of span typed in button
@Ovgodd Ovgodd force-pushed the fix/a11y-2344-subdocs-links-semantic branch from 57b7842 to 0b62029 Compare June 3, 2026 12:33
@Ovgodd Ovgodd requested a review from AntoLC June 3, 2026 12:33
@Ovgodd Ovgodd moved this from Backlog to In review in LaSuite Docs A11y Jun 3, 2026
@Ovgodd Ovgodd marked this pull request as ready for review June 3, 2026 12:34
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Size Change: 0 B

Total Size: 4.33 MB

📦 View Changed
Filename Size Change
apps/impress/out/_next/static/4f13ba17/_buildManifest.js 673 B +673 B (new file) 🆕
apps/impress/out/_next/static/8a6615e1/_buildManifest.js 0 B -673 B (removed) 🏆

compressed-size-action

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Walkthrough

This PR updates LinkSelected to render the interlinking control as a semantic anchor (Box as="a") instead of a button/span, removes the unused BoxButton import, retargets the click handlers to use anchor mouse events (preventDefault, open in new tab on modifier keys, otherwise router.push), and adds cursor and focus-outline styles. CHANGELOG.md gets a corresponding Unreleased → Added entry.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested reviewers

  • AntoLC
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: converting sub-document interlinks to use semantic anchor elements for accessibility.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose (accessibility improvement) and listing the specific proposals implemented in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/a11y-2344-subdocs-links-semantic

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx`:
- Around line 88-92: The CSS rule uses
".--docs--interlinking-link-inline-content:focus-visible" incorrectly as a
descendant selector, so update the stylesheet/StyledComponent for the
LinkSelected component (the selector targeting
--docs--interlinking-link-inline-content) to use the parent-focused selector
form (&:focus-visible) so the root link element receives the focus-visible
outline; ensure the outline and outline-offset declarations remain unchanged.
- Around line 64-67: The LinkSelected component currently renders a native
anchor via <Box as="a" href={href} ...>, which reintroduces native anchor
behavior; change it to render a non-anchor element (e.g., <Box as="span"> or
plain <span>) while preserving the existing onClick and onAuxClick handlers and
any accessibility attributes. Update the JSX in LinkSelected to remove the href
prop (or move it to a data-href attribute if the value must be preserved) and
ensure the className "--docs--interlinking-link-inline-content" and event
handlers remain on the new element so BlockNote/tiptap interlink behavior is not
overridden. Verify focus/keyboard interactions still work and adjust
role/tabIndex if needed to maintain accessibility.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0424edd9-68fe-4ab7-b43e-2ef50ea17a8e

📥 Commits

Reviewing files that changed from the base of the PR and between a78269a and 0b62029.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx

Comment on lines +64 to 67
<Box
as="a"
href={href}
className="--docs--interlinking-link-inline-content"
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jun 3, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx"
# Show around the cited lines
nl -ba "$FILE" | sed -n '40,90p'

Repository: suitenumerique/docs

Length of output: 106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx"
nl -ba "$FILE" | sed -n '40,90p'

Repository: suitenumerique/docs

Length of output: 106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx"
# Show with line numbers using cat -n
cat -n "$FILE" | sed -n '40,90p'

Repository: suitenumerique/docs

Length of output: 1769


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "BoxButton|--docs--interlinking-link-inline-content|LinkSelected" src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking src/frontend/apps/impress/src/features/docs/doc-editor -S

Repository: suitenumerique/docs

Length of output: 2799


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect LinkSelected usage and surrounding code
sed -n '1,180p' src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingLinkInlineContent.tsx

# Inspect CalloutBlock BoxButton usage (different component but may show intended patterns)
sed -n '80,170p' src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/CalloutBlock.tsx

# Find BoxButton implementation
rg -n "export (type|interface|const) BoxButton|function BoxButton|BoxButton\s*=" src/frontend -S

Repository: suitenumerique/docs

Length of output: 7467


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/frontend/apps/impress/src/components/BoxButton.tsx"
cat -n "$FILE" | sed -n '1,200p'

Repository: suitenumerique/docs

Length of output: 2655


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect Box implementation to understand how `as` is handled
FILE="src/frontend/apps/impress/src/components/Box.tsx"
if [ -f "$FILE" ]; then
  cat -n "$FILE" | sed -n '1,220p'
else
  echo "Missing $FILE; searching for Box.tsx..."
  fd -a "Box.tsx" src/frontend/apps/impress/src/components | head -n 20
fi

# Also check how Box is imported in LinkSelected
rg -n "import \\{ Box" src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx

Repository: suitenumerique/docs

Length of output: 7553


Avoid rendering a native <a> for this inline interlink control.
LinkSelected currently renders <Box as="a" href={href} ... onClick/onAuxClick> (lines 64-71), which reintroduces native anchor semantics and can conflict with the BlockNote/tiptap interlink behavior this component relies on. Render it as a non-anchor element (e.g., span) with the existing handlers instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx`
around lines 64 - 67, The LinkSelected component currently renders a native
anchor via <Box as="a" href={href} ...>, which reintroduces native anchor
behavior; change it to render a non-anchor element (e.g., <Box as="span"> or
plain <span>) while preserving the existing onClick and onAuxClick handlers and
any accessibility attributes. Update the JSX in LinkSelected to remove the href
prop (or move it to a data-href attribute if the value must be preserved) and
ensure the className "--docs--interlinking-link-inline-content" and event
handlers remain on the new element so BlockNote/tiptap interlink behavior is not
overridden. Verify focus/keyboard interactions still work and adjust
role/tabIndex if needed to maintain accessibility.

Copy link
Copy Markdown
Collaborator Author

@Ovgodd Ovgodd Jun 3, 2026

Choose a reason for hiding this comment

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

The point of this PR is to use a native <a href> for RGAA 6.1 compliance, a <span> with role="link" and tabindex is explicitly listed as insufficient in the accessibility audit. Native anchor behavior is handled by preventDefault in the click handler.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Ovgodd, that's a fair and clear correction — thank you. RGAA 6.1 (and the underlying WCAG success criterion 1.3.1) explicitly requires that links be marked up as native <a href> elements; a <span role="link" tabindex="0"> does not satisfy the criterion. Using <a href> with preventDefault in the click handler is precisely the right pattern here, and my previous suggestion to revert to a non-anchor element was incorrect in this context. I'll retract that concern.

One small thing worth verifying while you're here: in the $css block the focus-visible rule is written as a descendant selector:

.--docs--interlinking-link-inline-content:focus-visible { … }

Since the Box component is that element (not a parent of it), styled-components will look for a child with that class, so the rule may never fire. You likely want:

&:focus-visible { … }
/* or */
&.--docs--interlinking-link-inline-content:focus-visible { … }

✏️ Learnings added
Learnt from: Ovgodd
Repo: suitenumerique/docs PR: 2391
File: src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx:64-67
Timestamp: 2026-06-03T12:43:29.596Z
Learning: In the `LinkSelected` component (`src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx`), rendering as `<Box as="a" href={href}>` with `preventDefault` in the click handler is intentional and required for RGAA 6.1 / WCAG 1.3.1 compliance. A `<span role="link" tabindex="0">` is explicitly listed as insufficient in the project's accessibility audit. Do not suggest reverting to a non-anchor element.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx (1)

88-90: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use keyboard-targeted focus styling on Line 88.

&:focus-within also matches non-keyboard focus/descendants. For this anchor control, &:focus-visible better matches the accessibility intent for keyboard users.

Suggested fix
-        &:focus-within {
+        &:focus-visible {
           outline: 2px solid var(--c--globals--colors--brand-400);
           outline-offset: 2px;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx`
around lines 88 - 90, Replace the keyboard-focus styling selector on the
LinkSelected anchor control: change the CSS rule using "&:focus-within" to
"&:focus-visible" in the styled component (LinkSelected) so the visible outline
only appears for keyboard focus; update any related focus-offset/outline
declarations accordingly and consider keeping a graceful fallback for browsers
without :focus-visible support if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx`:
- Around line 88-90: Replace the keyboard-focus styling selector on the
LinkSelected anchor control: change the CSS rule using "&:focus-within" to
"&:focus-visible" in the styled component (LinkSelected) so the visible outline
only appears for keyboard focus; update any related focus-offset/outline
declarations accordingly and consider keeping a graceful fallback for browsers
without :focus-visible support if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e2284aba-767c-4900-9d19-a17959182cad

📥 Commits

Reviewing files that changed from the base of the PR and between 0b62029 and 884f5ca.

📒 Files selected for processing (1)
  • src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/LinkSelected.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accessibility bug Something isn't working triage

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

Links to sub-documents: <span> element not rendered and not keyboard-accessible

1 participant