Skip to content

PRDCT-692: open links that leave the docs in a new tab, marked ↗ - #1161

Open
Iamfle4ka wants to merge 4 commits into
mainfrom
PRDCT-692-external-links-new-tab
Open

Iamfle4ka wants to merge 4 commits into
mainfrom
PRDCT-692-external-links-new-tab

Conversation

@Iamfle4ka

@Iamfle4ka Iamfle4ka commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Why

A first-time reader went through Build an app locally on 4 October and suggested opening links in new tabs, or some other way back to the place in the guide. I checked where readers actually lose their place.

  • Inside the docs, they don't. I followed a link from build-locally to /cli/ and pressed Back, and the page came back to the same scroll position: 1817 px at desktop width and 3110 px at 375 px. Those links stay as they are.
  • Leaving the docs is where it happens. The free sign-up, the login, GitHub and vendor consoles have their own navigation, so after a few steps Back no longer leads to the guide. Build-locally's content has 7 such links, and none opened in a new tab.

What changed

  • src/integrations/external-links.mjs is a rehype plugin, added under markdown.rehypePlugins in astro.config.mjs (MDX inherits it). Every link to a host other than help.keboola.com gets:
    • target="_blank" and rel="noopener";
    • the class kbc-external;
    • a visually hidden "(opens in a new tab)" for screen readers.
  • That hidden text carries data-pagefind-ignore, so site search neither indexes it nor shows it in excerpts.
  • rel has no noreferrer, so Keboola's sign-up wizard still sees that a visitor came from the docs.
  • Two cases leave one part out:
    • a link inside a heading gets no hidden text, because the heading's anchor id and its table-of-contents entry are built from its text;
    • a link that holds only an image, like the Cursor install badge on /ai/mcp-server/, gets no arrow, which would otherwise wrap under the image.
  • The plugin covers markdown links, raw HTML blocks in .md pages (a hand-written <table>, for example), and JSX <a> in .mdx pages. An inline raw <a> tag in a paragraph gets the new tab and the arrow, but no hidden text, because its closing tag arrives separately. A link that already has a target keeps it.
  • src/components/Prereqs.astro passes its set:html strings through the same helper, because component HTML never reaches a rehype plugin. So "Create a free one" in the Before you start box opens in a new tab too.
  • custom.css draws a small ↗ after these links with content: '\2197' / ''. Screen readers skip the arrow and read the hidden text. Browsers that don't support that syntax fall back to a plain content: '\2197'.
  • No page changes. The markdown twins are built from the sources, so they don't change.

Checks

  • The build is clean. check-cli-reference finds 0 issues, audit-phase2 0 broken links and 0 missing images, and docs-link-redirect-check --site 0 blockers.
  • A scan of every docs page in the built site (index.html, not the 404 page) found 1941 external links inside page content (.sl-markdown-content).
    • All 1941 open in a new tab, and 1940 have the arrow; the one without it is the image badge.
    • No internal link changed, no heading id contains the hidden text, and every hidden span has data-pagefind-ignore.
  • Search, with the ranking the search box uses: "new tab", "open app" and "opens" return the same counts and the same top three on this build as on help.keboola.com today.
  • In the local production preview:
    • the arrow shows in light and dark, and the hidden text is clipped;
    • after a client-side (view transition) navigation from build-locally to /cli/, the link there keeps its arrow and target.
  • The first review raised seven points, and the second commit answers all of them. The two that mattered most: the hidden text was in search results, and a lone arrow sat under the Cursor badge. A second review passed, comparing this build with the live site on 11 search queries.

Not changed

  • Links outside page content: the header's API button, "Edit page" and the footer come from Starlight components.
  • The 404 page (src/pages/404.astro), which isn't built from markdown.
  • Internal links, including absolute https://help.keboola.com/… ones.

This touches site code, so the review bot will route it to a person.

🤖 Generated with Claude Code

A first-time reader who followed a link out to the platform (the free
sign-up, the login) or to GitHub lost the guide: those pages have their
own navigation, so Back doesn't lead back. Links inside the docs stay in
the same tab, because Back already returns to the same spot on the page
(checked at desktop and phone widths).

A rehype plugin, src/integrations/external-links.mjs, gives every link
to another host target="_blank", rel="noopener noreferrer", the class
kbc-external and a visually hidden "(opens in a new tab)". It covers
markdown links, raw HTML blocks in .md pages and JSX <a> in .mdx pages.
Prereqs.astro passes its set:html strings through the same helper, so
"Create a free one" opens in a new tab too. custom.css draws a small ↗
after those links; screen readers skip it and read the hidden text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Iamfle4ka Iamfle4ka added the site-tooling Touches build config, CI, scripts or runtime code — the reviewer bot always routes these to a human label Oct 6, 2026
@vercel

vercel Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
connection-docs Ready Ready Preview Oct 8, 2026 3:17pm UTC

Request Review

@linear-code

linear-code Bot commented Oct 6, 2026

Copy link
Copy Markdown

PRDCT-692

Review of the first commit found that Pagefind indexed the hidden
"(opens in a new tab)": it showed up in search excerpts and pulled
pages up for "new tab". The hidden span now carries
data-pagefind-ignore, and the three test queries rank the same as on
help.keboola.com.

A link inside a heading gets no hidden text, because the anchor id and
the table-of-contents entry come from the heading's text. A link that
holds only an image (the Cursor badge on /ai/mcp-server/) gets no
arrow, which wrapped onto its own line under the image.

rel is "noopener" only, so Keboola's own sites still see the docs as
the referrer. The string helper also handles attributes in any order
and inline raw <a> tags whose closing tag sits in another node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
astro.config.mjs conflicted on one line: this branch imports
external-links.mjs and main now imports pagefind-titles.mjs in the same
place. Both imports stay. The build is clean (373 pages, pagefind-titles
writes 372 rows), and all 1941 external content links still get the
hidden hint with data-pagefind-ignore, 1940 of them the arrow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
astro.config.mjs conflicted in the markdown block: main added
remarkStripComments to remarkPlugins, and this branch added
rehypePlugins: [externalLinks] next to it. Both stay. The build is clean
(374 pages), no VERIFY comment reaches the HTML, and all 1940 external
content links get the hidden hint with data-pagefind-ignore, 1939 of
them the arrow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — bb1cc3ce Deployed Oct 8, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

site-tooling Touches build config, CI, scripts or runtime code — the reviewer bot always routes these to a human

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant