Skip to Content
HelpHelp Improvement 9 — Section Deep Links

Help Improvement 9 — Section Deep Links

Status: [To Build]

Purpose: Help icons on feature pages currently link to the topic root (e.g. /help/blog). When the relevant information is in a specific section mid-page, the user has to scroll to find it. Adding anchor IDs to section headings enables ? buttons to link directly to the relevant section.


What Changes

  1. Every section heading in HelpPage gets an id attribute derived from the heading text.
  2. On page load, HelpPage scrolls to the #hash in the URL (if present).
  3. Each heading renders a small # link (visible on hover) for copy-to-clipboard navigation.
  4. HelpTrigger and inline help Links can append #section-id to their href.

Slug Generation

A pure slugify function converts heading text to an id-safe string:

// packages/ui/src/lib/slugify.ts export function slugify(text: string): string { return text .toLowerCase() .replace(/[^a-z0-9\s-]/g, "") // remove non-alphanumeric .trim() .replace(/\s+/g, "-"); // spaces → hyphens } // Examples: // "The approval workflow" → "the-approval-workflow" // "Status guide" → "status-guide" // "What are Blog Posts?" → "what-are-blog-posts"

HelpPage Section Heading Render

For every section that has a heading field, add the id and hover anchor:

// packages/ui/src/HelpPage.tsx import { slugify } from "./lib/slugify"; import { Link2 } from "lucide-react"; function SectionHeading({ text }: { text: string }) { const id = slugify(text); return ( <h2 id={id} className="text-base font-semibold mb-3 flex items-center gap-2 group scroll-mt-6" > {text} <a href={`#${id}`} className="opacity-0 group-hover:opacity-100 transition-opacity text-muted-foreground hover:text-foreground" aria-label={`Link to ${text}`} > <Link2 className="w-3.5 h-3.5" /> </a> </h2> ); }

Replace all inline <h2>{section.heading}</h2> calls with <SectionHeading text={section.heading} />.


Scroll to Hash on Load

// packages/ui/src/HelpPage.tsx "use client"; import { useEffect } from "react"; // Inside HelpPage component: useEffect(() => { const hash = window.location.hash.slice(1); if (!hash) return; const el = document.getElementById(hash); if (el) { // Small delay so the page has painted before scrolling setTimeout(() => el.scrollIntoView({ behavior: "smooth", block: "start" }), 100); } }, [data.slug]); // re-run when slug changes (drawer navigation)

HelpTrigger gains an optional section prop:

// apps/dashboard/src/components/help/HelpTrigger.tsx interface HelpTriggerProps { slug: string; section?: string; // heading text OR pre-computed slug label?: string; } export function HelpTrigger({ slug, section, label }: HelpTriggerProps) { const { open } = useHelpDrawer(); const hash = section ? `#${slugify(section)}` : ""; function handleClick() { open(slug); if (hash) { // Scroll after drawer animation completes setTimeout(() => { const el = document.getElementById(hash.slice(1)); el?.scrollIntoView({ behavior: "smooth", block: "start" }); }, 300); } } return ( <button onClick={handleClick} title={label ?? "Help"} ...> <HelpCircle className="w-4 h-4" /> </button> ); }

Example usage — the ? icon next to the approval section of the blog page opens the drawer and scrolls to “The approval workflow”:

<HelpTrigger slug="blog" section="The approval workflow" label="Help: Blog Approvals" />

Affected Files

FileChange
packages/ui/src/lib/slugify.tsNew utility
packages/ui/src/HelpPage.tsxAdd id to section headings; SectionHeading component; scroll-to-hash on mount
apps/dashboard/src/components/help/HelpTrigger.tsxAdd section prop + scroll-after-open

© 2026 Leadmetrics — Internal use only