diff --git a/src/lib/components/CopyClipboard.svelte b/src/lib/components/CopyClipboard.svelte
index 01341090af948086dd506e3d93809ee628b781d5..fc9c7d7dd0a13d33341b8fada0f1b4432baca1c3 100644
--- a/src/lib/components/CopyClipboard.svelte
+++ b/src/lib/components/CopyClipboard.svelte
@@ -1,9 +1,9 @@
 <script lang="ts">
   import { onMount } from "svelte"
 
-  export let value
+  export let value: string
 
-  let textarea
+  let textarea: HTMLTextAreaElement
 
   onMount(() => {
     textarea.select()
diff --git a/src/lib/components/transverse_pages/AnchorTitle.svelte b/src/lib/components/transverse_pages/AnchorTitle.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..f7c9fa443603c337fc6e96765a8515dd7d64bb56
--- /dev/null
+++ b/src/lib/components/transverse_pages/AnchorTitle.svelte
@@ -0,0 +1,50 @@
+<script lang="ts">
+  import CopyClipboard from "$lib/components/CopyClipboard.svelte"
+
+  export let id: string
+  export let tag = "h2"
+
+  let clipboardElement: HTMLElement
+  let linkCopied = false
+
+  function copyUrl() {
+    if (id === undefined) {
+      return
+    }
+    const baseUrl = window.location.origin + window.location.pathname
+    const urlWithAnchor = `${baseUrl}#${id}`
+    const copyClipboard = new CopyClipboard({
+      target: clipboardElement,
+      props: { value: urlWithAnchor },
+    })
+    copyClipboard.$destroy()
+    linkCopied = true
+    setTimeout(() => {
+      linkCopied = false
+    }, 2000)
+  }
+</script>
+
+<div bind:this={clipboardElement} />
+
+<svelte:element
+  this={tag}
+  {...$$restProps}
+  {id}
+  class="relative group {$$props.class ?? ''}"
+>
+  <button class="absolute -ml-8 mt-1 h-6" on:click={copyUrl}>
+    <iconify-icon
+      class="group-hover:text-black text-neutral-400"
+      icon="ri-links-line"
+    />
+
+    {#if linkCopied}
+      <span
+        class="absolute -top-2 left-1/2 -translate-x-1/2 -translate-y-full bg-le-vert-800 text-white px-2 py-1 text-sm text-nowrap rounded-md font-sans font-normal z-50"
+        >Lien copié !</span
+      >
+    {/if}
+  </button>
+  <slot />
+</svelte:element>
diff --git a/src/lib/components/transverse_pages/TitreH2AvecAncre.svelte b/src/lib/components/transverse_pages/TitreH2AvecAncre.svelte
deleted file mode 100644
index d93c66e263bd7ba2e3c7530a39500565e2170693..0000000000000000000000000000000000000000
--- a/src/lib/components/transverse_pages/TitreH2AvecAncre.svelte
+++ /dev/null
@@ -1,34 +0,0 @@
-<script>
-  export let id = ""
-  export let h2class = ""
-  let linkCopied = false
-
-  function copyUrl(event) {
-    const titleElement = event.target.parentNode
-    const baseUrl = window.location.origin + window.location.pathname
-    const urlWithAnchor = `${baseUrl}#${id}`
-    navigator.clipboard.writeText(urlWithAnchor)
-    linkCopied = true
-    setTimeout(() => {
-      linkCopied = false
-    }, 2000)
-  }
-</script>
-
-<h2 {id} class="group {h2class}">
-  <div class="relative inline-flex">
-    <iconify-icon
-      class="group-hover:text-black text-neutral-400 absolute -left-8 -top-5"
-      icon="ri-links-line"
-      on:click={copyUrl}
-    />
-
-    {#if linkCopied}
-      <span
-        class="bg-le-vert-800 text-white px-2 py-1 text-sm -top-12 -left-14 absolute text-nowrap rounded-md font-sans font-normal z-50"
-        >Lien copié !</span
-      >
-    {/if}
-  </div>
-  <slot />
-</h2>
diff --git a/src/routes/welcome/+page.svelte b/src/routes/welcome/+page.svelte
index 37f932f4b1b4277724f2c360508181eaa95936ed..51e975b33eea0838a55e38d0c324601ec3f13249 100644
--- a/src/routes/welcome/+page.svelte
+++ b/src/routes/welcome/+page.svelte
@@ -12,9 +12,9 @@
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
   import { auditQuerySingleton } from "$lib/auditors/queries"
-  import TitreH2AvecAncre from "$lib/components/transverse_pages/TitreH2AvecAncre.svelte"
   import PictoOpenFisca from "$lib/components/pictos/PictoOpenFisca.svelte"
   import WelcomeSearch from "$lib/components/search/WelcomeSearch.svelte"
+  import AnchorTitle from "$lib/components/transverse_pages/AnchorTitle.svelte"
   import VariableDetail from "$lib/components/variables/VariableDetail.svelte"
   import {
     buildDecompositionByNameFromCore,
@@ -313,12 +313,13 @@
   <section
     class="grid grid-cols-4 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-[#E3E4D6] font-serif text-base 2xl:text-lg"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="caracteristiques-simulateur"
-      h2class="justify-self-center max-w-prose text-2xl font-light col-span-4 text-center font-sans"
+      class="justify-self-center max-w-prose text-2xl font-light col-span-4 text-center font-sans"
+      tag="h2"
     >
       Les caractéristiques du simulateur ⬇️
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     <div class="col-span-4 md:col-span-2 xl:col-span-1">
       <div class="text-center">
@@ -475,13 +476,14 @@
     id="dispositif-couverts"
     class="grid grid-cols-2 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-white text-base 2xl:text-lg"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="dispositifs-couverts-simulateur"
-      h2class="text-2xl font-light col-span-2 text-center justify-self-center font-sans"
+      class="text-2xl font-light col-span-2 text-center justify-self-center font-sans"
+      tag="h2"
     >
       Les {withLinkedVariableNames.length} dispositifs couverts par le simulateur
       LexImpact socio-fiscal&nbsp;:
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     {#each waterfallsDecompositions as { waterfall, visibleDecompositions }}
       {#if visibleDecompositions.length > 0}
@@ -621,9 +623,10 @@
   <section
     class="fond grid grid-cols-4 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-white"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="impacts-budgetaires"
-      h2class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      tag="h2"
     >
       <span
         class="border-b-2 border-black pb-3 font-serif italic font-light relative z-10"
@@ -634,7 +637,7 @@
       <br />
       Calculer les impacts budgétaires d’une réforme de CSG, impôt sur le revenu
       ou allocations familiales
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     <div
       class="font-serif text-lg col-span-4 xl:col-span-2 justify-self-center lg:justify-self-end"
@@ -719,9 +722,10 @@
   <section
     class="grid grid-cols-4 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-[#E3E4D6]"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="feuile-de-paie"
-      h2class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      tag="h2"
     >
       <span
         class="border-b-2 border-black pb-3 font-serif italic font-light relative z-10"
@@ -732,7 +736,7 @@
       <br />
       Visualiser l’ensemble des impôts, cotisations et prestations sociales
       <br />qui affectent un cas type
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     <div
       class="font-serif text-lg col-span-4 lg:col-span-2 justify-self-center lg:justify-self-end"
@@ -782,9 +786,10 @@
   <section
     class="grid grid-cols-4 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-[#D7E2F4]"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="graphiques-cas-types"
-      h2class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      tag="h2"
     >
       <span
         class="border-b-2 border-black pb-3 font-serif italic font-light relative z-10"
@@ -795,7 +800,7 @@
       <br />
       Consulter l’évolution du système socio-fiscal d’un cas type selon son revenu
       principal
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     <div
       class="font-serif text-lg col-span-4 lg:col-span-2 justify-self-center lg:justify-self-end"
@@ -888,9 +893,10 @@
   <section
     class="grid grid-cols-4 gap-x-12 px-10 md:px-20 lg:px-40 pb-20 pt-10 gap-y-12 bg-white fond"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="gagnants-perdants"
-      h2class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      class="justify-self-center text-2xl font-bold col-span-4 text-center max-w-prose"
+      tag="h2"
     >
       <span
         class="border-b-2 border-black pb-3 font-serif italic font-light relative z-10"
@@ -901,7 +907,7 @@
       <br />
       Calculer les impacts sur la population d’une réforme de CSG, impôt sur le revenu
       ou allocations familiales
-    </TitreH2AvecAncre>
+    </AnchorTitle>
 
     <div
       class="font-serif text-lg col-span-4 lg:col-span-2 justify-self-center lg:justify-self-end"
@@ -981,12 +987,13 @@
   <section
     class="flex flex-col justify-center px-10 md:px-20 lg:px-40 pb-20 pt-10 bg-[#240B36] text-white font-serif text-lg"
   >
-    <TitreH2AvecAncre
+    <AnchorTitle
       id="graphiques-cas-types"
-      h2class="text-2xl font-bold font-sans text-center mb-10"
+      class="text-2xl font-bold font-sans text-center mb-10"
+      tag="h2"
     >
       Un simulateur qui s'appuie sur le moteur de calcul <PictoOpenFisca /> OpenFisca
-    </TitreH2AvecAncre>
+    </AnchorTitle>
     <div class="flex gap-12 flex-col md:flex-row justify-center items-start">
       <div class="max-w-screen-lg">
         <p>