#13224 · @kdcokenny · opened Feb 11, 2026 at 11:17 PM UTC · last updated Mar 21, 2026 at 11:12 AM UTC

feat(docs): add copy page markdown action to docs title

appfeat
59
+2601820 files

Score breakdown

Impact

7.0

Clarity

9.0

Urgency

2.0

Ease Of Review

8.0

Guidelines

8.0

Readiness

6.0

Size

3.0

Trust

9.0

Traction

2.0

Summary

This PR adds a "Copy page as Markdown" action button to the documentation page titles. This new feature allows users to quickly copy the entire page content as Markdown to their clipboard, improving content reusability from the docs.

Open in GitHub

Description

Summary

Adds a "Copy page as Markdown" action button to the docs page title area, allowing users to copy the full page content as Markdown to their clipboard.

Closes #6453

Changes

  • New PageTitle.astro component with copy-to-clipboard functionality
  • Astro config updated to integrate the component override
  • i18n strings added for all 18 supported locales (copyPage.button, copyPage.success, copyPage.error)
<img width="1489" height="372" alt="image" src="https://github.com/user-attachments/assets/bba5781e-45d3-473b-9b87-8b17adc468ad" /> <img width="899" height="244" alt="image" src="https://github.com/user-attachments/assets/5c65ae6c-245d-49cf-8e63-9e48797737b1" /> <img width="423" height="869" alt="image" src="https://github.com/user-attachments/assets/61bf1a90-935a-4e09-9e05-5eedd5f3c067" /> (i can also change it to hide on mobile if you prefer)

Testing

  1. Run docs locally: bun run --cwd packages/web dev
  2. Visit http://localhost:4321
  3. Navigate to any docs page and verify the copy button appears next to the page title
  4. Click the button and paste into a text editor — should contain the page's Markdown content
  5. Verify the success/error tooltip feedback appears
  6. Test with different locales if possible

Linked Issues

#6453 [FEATURE]: Add "Copy Page as Markdown" button to Docs

View issue

Comments

No comments.

Changed Files

packages/web/astro.config.mjs

+10
@@ -298,6 +298,7 @@ export default defineConfig({
Header: "./src/components/Header.astro",
Footer: "./src/components/Footer.astro",
SiteTitle: "./src/components/SiteTitle.astro",
PageTitle: "./src/components/PageTitle.astro",
},
plugins: [
theme({

packages/web/src/components/PageTitle.astro

+2050
@@ -0,0 +1,205 @@
---
import Default from "@astrojs/starlight/components/PageTitle.astro"
const { slug } = Astro.locals.starlightRoute.entry
const description = Astro.locals.starlightRoute.entry.data.description
const isHome = slug === ""
const t = Astro.locals.t as (key: string, fallback?: string) => string
const copyPage = t("docs.copy_page", "Copy page")
const copying = t("docs.copying", "Copying…")
const copied = t("share.copied", "Copied!")
const failed = t("share.error", "Error")
---
<div class="page-title-row">
<Default {...Astro.props}><slot /></Default>
{!isHome && (
<button
type="button"
class="copy-page"
data-slug={slug}
data-label-idle={copyPage}
data-label-copying={copying}
data-label-copied={copied}
data-label-failed={failed}
aria-label={copyPage}
title={copyPage}
>
<svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1

packages/web/src/content/i18n/ar.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "مطابقات",
"share.result_one": "نتيجة",
"share.result_other": "نتائج",
"share.debug_key": "المفتاح"
"share.debug_key": "المفتاح",
"docs.copy_page": "نسخ الصفحة",
"docs.copying": "جارٍ النسخ…"
}

packages/web/src/content/i18n/bs.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "podudaranja",
"share.result_one": "rezultat",
"share.result_other": "rezultati",
"share.debug_key": "Ključ"
"share.debug_key": "Ključ",
"docs.copy_page": "Kopiraj stranicu",
"docs.copying": "Kopiranje…"
}

packages/web/src/content/i18n/da.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "træf",
"share.result_one": "resultat",
"share.result_other": "resultater",
"share.debug_key": "Nøgle"
"share.debug_key": "Nøgle",
"docs.copy_page": "Kopiér side",
"docs.copying": "Kopierer…"
}

packages/web/src/content/i18n/de.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "Treffer",
"share.result_one": "Ergebnis",
"share.result_other": "Ergebnisse",
"share.debug_key": "Schlüssel"
"share.debug_key": "Schlüssel",
"docs.copy_page": "Seite kopieren",
"docs.copying": "Kopieren…"
}

packages/web/src/content/i18n/en.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "matches",
"share.result_one": "result",
"share.result_other": "results",
"share.debug_key": "Key"
"share.debug_key": "Key",
"docs.copy_page": "Copy page",
"docs.copying": "Copying…"
}

packages/web/src/content/i18n/es.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "coincidencias",
"share.result_one": "resultado",
"share.result_other": "resultados",
"share.debug_key": "Clave"
"share.debug_key": "Clave",
"docs.copy_page": "Copiar página",
"docs.copying": "Copiando…"
}

packages/web/src/content/i18n/fr.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "correspondances",
"share.result_one": "résultat",
"share.result_other": "résultats",
"share.debug_key": "Clé"
"share.debug_key": "Clé",
"docs.copy_page": "Copier la page",
"docs.copying": "Copie…"
}

packages/web/src/content/i18n/it.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "corrispondenze",
"share.result_one": "risultato",
"share.result_other": "risultati",
"share.debug_key": "Chiave"
"share.debug_key": "Chiave",
"docs.copy_page": "Copia pagina",
"docs.copying": "Copia in corso…"
}

packages/web/src/content/i18n/ja.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "一致",
"share.result_one": "結果",
"share.result_other": "結果",
"share.debug_key": "キー"
"share.debug_key": "キー",
"docs.copy_page": "ページをコピー",
"docs.copying": "コピー中…"
}

packages/web/src/content/i18n/ko.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "일치",
"share.result_one": "결과",
"share.result_other": "결과",
"share.debug_key": "키"
"share.debug_key": "키",
"docs.copy_page": "페이지 복사",
"docs.copying": "복사 중…"
}

packages/web/src/content/i18n/nb.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "treff",
"share.result_one": "resultat",
"share.result_other": "resultater",
"share.debug_key": "Nøkkel"
"share.debug_key": "Nøkkel",
"docs.copy_page": "Kopier side",
"docs.copying": "Kopierer…"
}

packages/web/src/content/i18n/pl.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "dopasowania",
"share.result_one": "wynik",
"share.result_other": "wyniki",
"share.debug_key": "Klawisz"
"share.debug_key": "Klawisz",
"docs.copy_page": "Kopiuj stronę",
"docs.copying": "Kopiowanie…"
}

packages/web/src/content/i18n/pt-BR.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "correspondências",
"share.result_one": "resultado",
"share.result_other": "resultados",
"share.debug_key": "Chave"
"share.debug_key": "Chave",
"docs.copy_page": "Copiar página",
"docs.copying": "Copiando…"
}

packages/web/src/content/i18n/ru.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "совпадений",
"share.result_one": "результат",
"share.result_other": "результатов",
"share.debug_key": "Ключ"
"share.debug_key": "Ключ",
"docs.copy_page": "Копировать страницу",
"docs.copying": "Копирование…"
}

packages/web/src/content/i18n/th.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "รายการที่ตรงกัน",
"share.result_one": "ผลลัพธ์",
"share.result_other": "ผลลัพธ์",
"share.debug_key": "คีย์"
"share.debug_key": "คีย์",
"docs.copy_page": "คัดลอกหน้า",
"docs.copying": "กำลังคัดลอก…"
}

packages/web/src/content/i18n/tr.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "eşleşme",
"share.result_one": "sonuç",
"share.result_other": "sonuç",
"share.debug_key": "Anahtar"
"share.debug_key": "Anahtar",
"docs.copy_page": "Sayfayı kopyala",
"docs.copying": "Kopyalanıyor…"
}

packages/web/src/content/i18n/zh-CN.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "匹配项",
"share.result_one": "结果",
"share.result_other": "结果",
"share.debug_key": "键"
"share.debug_key": "键",
"docs.copy_page": "复制页面",
"docs.copying": "复制中…"
}

packages/web/src/content/i18n/zh-TW.json

+31
@@ -71,5 +71,7 @@
"share.match_other": "符合項目",
"share.result_one": "結果",
"share.result_other": "結果",
"share.debug_key": "金鑰"
"share.debug_key": "金鑰",
"docs.copy_page": "複製頁面",
"docs.copying": "複製中…"
}