Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to
- ♿️(frontend) add aria-hidden to decorative avatar SVGs in share modal #2324
- 🏗️(frontend) move comments to its own folder feature #2374
- ♿️(frontend) align mobile header menu aria-label i18n pattern #2377
- ♿️(frontend) use anchor links for interlinking sub-documents #2391

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { css } from 'styled-components';

import { Box, BoxButton, Text } from '@/components';
import { Box, Text } from '@/components';
import SelectedPageIcon from '@/docs/doc-editor/assets/doc-selected.svg';
import { getEmojiAndTitle, useDoc } from '@/docs/doc-management/';

Expand Down Expand Up @@ -41,19 +41,17 @@ export const LinkSelected = ({
const router = useRouter();
const href = `/docs/${docId}/`;

const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();

// If ctrl or command is pressed, it opens a new tab. If shift is pressed, it opens a new window
if (e.metaKey || e.ctrlKey || e.shiftKey) {
window.open(href, '_blank');
return;
}
void router.push(href);
};

// This triggers on middle-mouse click
const handleAuxClick = (e: React.MouseEvent<HTMLButtonElement>) => {
const handleAuxClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
if (e.button !== 1) {
return;
}
Expand All @@ -63,8 +61,9 @@ export const LinkSelected = ({
};

return (
<BoxButton
as="span"
<Box
as="a"
href={href}
className="--docs--interlinking-link-inline-content"
Comment on lines +64 to 67
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.

data-href={href}
onClick={handleClick}
Expand All @@ -75,6 +74,7 @@ export const LinkSelected = ({
display: inline;
padding: 0.1rem 0.4rem;
border-radius: 4px;
cursor: pointer;
& svg {
position: relative;
top: 2px;
Expand All @@ -85,6 +85,10 @@ export const LinkSelected = ({
--c--contextuals--background--semantic--contextual--primary
);
}
&:focus-within {
outline: 2px solid var(--c--globals--colors--brand-400);
outline-offset: 2px;
}
transition: background-color var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);

Expand Down Expand Up @@ -129,6 +133,6 @@ export const LinkSelected = ({
{titleWithoutEmoji}
</Box>
</Text>
</BoxButton>
</Box>
);
};
Loading