Skip to content

fix(core): keep same-page anchor links in the same tab#1901

Open
scottbuscemi wants to merge 2 commits into
mainfrom
fix/anchor-links-open-self
Open

fix(core): keep same-page anchor links in the same tab#1901
scottbuscemi wants to merge 2 commits into
mainfrom
fix/anchor-links-open-self

Conversation

@scottbuscemi

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes same-page anchor links (e.g. #section) in Portable Text content opening in a new tab. EmDash renders the Portable Text link mark via its own Link.astro component (packages/core/src/components/marks.ts maps linkLink.astro), which emitted target="_blank" whenever the stored mark had blank: true — with no special-casing for on-page anchors. That meant a same-page jump could open in a new tab, which is never desirable.

Link.astro now treats any href starting with # as a same-page anchor and forces same-tab behavior (no target/rel), regardless of the mark's blank flag. External links with blank: true still open in a new tab as before.

This is entirely EmDash's own render component — not an upstream Astro / astro-portabletext default.

Closes #

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (for emdash/core, the changed package; a pre-existing @emdash-cms/cloudflare resolution error requires a core build and is unrelated to this change)
  • pnpm lint passes (lint:json reports 0 diagnostics)
  • pnpm test passes (or targeted tests for my change) — test:repro suite green
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). n/a — no admin UI strings changed.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion. n/a — bug fix.

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8 (opencode)

Screenshots / test output

TDD: added packages/core/tests/repro/link-mark-anchor.render.test.ts (AstroContainer render test). Failed before the fix (#section + blank: true rendered target="_blank"), passes after. Regression guard confirms external links with blank: true still open in a new tab.

@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8322daf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/core size/M labels Jul 9, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1901

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1901

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1901

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1901

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1901

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1901

emdash

npm i https://pkg.pr.new/emdash@1901

create-emdash

npm i https://pkg.pr.new/create-emdash@1901

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1901

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1901

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1901

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1901

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1901

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1901

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1901

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1901

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1901

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1901

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1901

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1901

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1901

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1901

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1901

commit: 8322daf

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 8322daf Jul 09 2026, 07:50 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 8322daf Jul 09 2026, 07:47 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-do 8322daf Jul 09 2026, 07:47 PM

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a focused, well-scoped bug fix: EmDash's own Link.astro component was unconditionally emitting target="_blank" whenever the stored Portable Text link mark had blank: true, which meant plain same-page anchors like #section would open in a new tab. The change forces same-tab behavior only when the resolved href starts with #, leaving external links unchanged.

I checked the changed component, the sanitizeHref utility it depends on, the mark-component map, the new AstroContainer render regression test, and the changeset. The fix is minimal and correct: queries against the sanitized href, so unsafe/empty hrefs that sanitizeHref collapses to "#" also stay same-tab, which is harmless. Relative paths with fragments (/page#section) still respect the existing blank behavior, which matches the stated intent.

The PR also adds a repro test with the expected before/after failure pattern and a proper emdash patch changeset. No localization, SQL, authorization, or API route concerns are involved. LGTM.

@github-actions github-actions Bot added review/approved Approved; no new commits since query-count changed PR diff modifies query-count snapshot files and removed review/needs-review No maintainer or bot review yet labels Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Query-count snapshot changes

4 routes changed, total Δ +4 queries.

SQLite

Route Before After Δ
GET /search (cold) 10 11 +1
GET /search (warm) 10 11 +1

D1

Route Before After Δ
GET /search (cold) 21 22 +1
GET /search (warm) 10 11 +1

Comparing snapshot files between base and head. Updated automatically on each push.

@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@github-actions github-actions Bot mentioned this pull request Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core overlap query-count changed PR diff modifies query-count snapshot files review/approved Approved; no new commits since size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant