A frontmatter-driven card that appears in the right rail of any docs page (below the table of contents) to point readers at related tutorials, blog posts, and an optional call-to-action button.
No imports. No per-page wiring. No JavaScript. Just add a learnMore: block to a page's frontmatter and the card renders itself. Omit it and the card stays hidden.
← Back to the main README.
- Quick start: copy-paste example
- What it looks like and where it lives
- Frontmatter shape
- Field reference
- Variations and recipes ← most authors land here
- Recipe 1: Tutorial page (full card)
- Recipe 2: Concept page (related reading only)
- Recipe 3: Quickstart with a single CTA
- Recipe 4: Reference page (related guides)
- Recipe 5: Custom section headings
- Recipe 6: External versus internal links
- Recipe 7: Custom card title
- Recipe 8: Tutorials-only or CTA-only
- Testing locally
- Troubleshooting
- Real pages already using this
- Architecture
- Theming
- Figma
- Gotchas
Open the page you want to add the card to. At the top, inside the existing --- frontmatter block, paste this and edit the labels and hrefs:
learnMore:
tutorials:
- label: Your first hypertable
href: /build/how-to/your-first-hypertable/
- label: Connect your app
href: /get-started/quickstart/connect-your-app/
relatedPosts:
- label: Why use hypertables
href: https://www.timescale.com/blog/why-hypertables/
cta:
label: Try for free
href: https://console.cloud.tigerdata.com/signupSave, run pnpm dev, and the card appears in the right rail. That's it.
The card renders inside the right rail (the column that holds the page's table of contents), pinned to the bottom of that column so it stays anchored even on long pages. On mobile and tablet (below 1024px) the right rail collapses, so the card hides automatically along with the TOC.
Visually:
┌─ Page content ───────────┬─ Right rail ─────────────┐
│ │ On this page │
│ # Article title │ - Section 1 │
│ │ - Section 2 │
│ Lorem ipsum… │ - Section 3 │
│ │ │
│ ## Section 1 │ │
│ … │ │
│ │ ┌──────────────────┐ │
│ ## Section 2 │ │ 🎓 Learn more │ │
│ … │ │ │ │
│ │ │ Tutorials │ │
│ │ │ → Tutorial A │ │
│ │ │ → Tutorial B │ │
│ │ │ │ │
│ │ │ Related blog… │ │
│ │ │ ↗ Post X │ │
│ │ │ │ │
│ │ │ ┌─────────────┐ │ │
│ │ │ │ Try for free│ │ │
│ │ │ └─────────────┘ │ │
│ │ └──────────────────┘ │
└──────────────────────────┴──────────────────────────┘
A single top-level learnMore: key with three optional children: tutorials, relatedPosts, and cta. Plus a few optional overrides for headings.
---
title: My page title
description: My page description
learnMore:
title: Learn more # optional, defaults to "Learn more"
tutorials: # optional list
- label: Your first hypertable
href: /build/how-to/your-first-hypertable/
- label: Connect your app
href: /get-started/quickstart/connect-your-app/
tutorialsHeading: Tutorials # optional, defaults to "Tutorials"
relatedPosts: # optional list
- label: Why use hypertables
href: https://www.timescale.com/blog/why-hypertables/
relatedPostsHeading: Related blog posts # optional, default shown
cta: # optional single CTA button
label: Try for free
href: https://console.cloud.tigerdata.com/signup
---Every field is optional. If tutorials, relatedPosts, and cta are all absent (or empty), the card hides itself completely, with no empty card and no broken layout.
| Field | Type | Default | Notes |
|---|---|---|---|
title |
string | "Learn more" |
Card title shown next to the graduation-cap icon. |
tutorials |
{ label, href }[] |
None | Internal tutorial-style links. Render with a right-arrow icon. |
tutorialsHeading |
string | "Tutorials" |
Heading above the tutorials list. |
relatedPosts |
{ label, href }[] |
None | External references (blog posts, articles, third-party docs). Render with an external-link icon. |
relatedPostsHeading |
string | "Related blog posts" |
Heading above the related posts list. |
cta |
{ label, href } |
None | A single outlined button at the bottom of the card. Solid fill on hover/focus. |
- Relative URLs (
/build/foo/) render as in-site links and open in the same tab. - Absolute URLs (
https://…) automatically gettarget="_blank"andrel="noopener noreferrer".
Detection is ^https?:// only. Protocol-relative (//example.com), mailto:, and tel: URLs all fall through to the in-site path. Always use a leading slash for in-site links so the relative-vs-absolute logic stays predictable.
These are copy-paste-ready. Pick the closest match, drop it into your page's frontmatter, edit the labels and hrefs.
The full card: next tutorials, related blog posts, and a sign-up CTA. Best for end-of-tutorial pages where you want to keep readers in the funnel.
---
title: Build hybrid search with BM25 and vector similarity
description: Combine keyword search and semantic vector search in PostgreSQL.
learnMore:
tutorials:
- label: Understand pg_textsearch and BM25 search
href: /learn/search/using-pg-textsearch/
- label: Understand pgvector and pgvectorscale
href: /learn/search/pgvector-pgvectorsearch/
- label: Key vector database concepts
href: /learn/search/key-vector-database-concepts/
relatedPosts:
- label: Hybrid search with pg_textsearch and pgvectorscale
href: https://www.timescale.com/blog/hybrid-search/
- label: Why we built pg_textsearch
href: https://www.timescale.com/blog/pg-textsearch-bm25/
cta:
label: Try for free
href: https://console.cloud.tigerdata.com/signup
---This pattern is live on src/content/docs/build/examples/hybrid-search.mdx (see PR #267).
For a conceptual learn/ page where the goal is to deepen understanding, not push action. Skip the CTA and tutorials, just show related blog posts.
---
title: Understand hypertables
description: How hypertables partition time-series data automatically.
learnMore:
relatedPosts:
- label: When to use hypertables
href: https://www.timescale.com/blog/when-to-hypertable/
- label: Hypertables versus partitioned tables
href: https://www.timescale.com/blog/hypertables-vs-partitioning/
---For a quickstart's final page, give readers one obvious next step.
---
title: You're all set
description: Wrap up the 5-minute quickstart.
learnMore:
cta:
label: Open Tiger Cloud Console
href: https://console.cloud.tigerdata.com/
---For an API or SQL reference page, point readers to the practical how-tos. Tutorials only, no CTA, no blog posts.
---
title: create_hypertable()
description: Reference for the create_hypertable SQL function.
learnMore:
tutorials:
- label: Your first hypertable
href: /build/how-to/your-first-hypertable/
- label: Choose a partitioning column
href: /build/how-to/choose-a-partitioning-column/
---Override the default headings when "Tutorials" or "Related blog posts" doesn't quite fit. Useful when the linked items aren't strictly tutorials (for example, video walkthroughs).
---
title: Migrate from PostgreSQL
learnMore:
tutorialsHeading: Next steps
tutorials:
- label: Live migration walkthrough
href: /migrate/live-migration/
- label: Validate after migration
href: /migrate/validate/
relatedPostsHeading: Customer stories
relatedPosts:
- label: How Company X migrated 8 TB in a weekend
href: https://www.timescale.com/blog/customer-x/
---The component decides target tab from the href, not from which list the link is in. So you can put an external link in tutorials (it'll still open in a new tab), but stylistically the icon won't match (you'll get a right-arrow on an external link). Keep the convention:
tutorials→ internal docs paths starting with/relatedPosts→ absolutehttps://…URLs
learnMore:
tutorials:
- label: Internal — opens in same tab
href: /build/how-to/something/
relatedPosts:
- label: External — opens in new tab
href: https://www.timescale.com/blog/something/Replace the default "Learn more" title when something else reads better in context (for example, on a troubleshooting page).
learnMore:
title: Need more help?
tutorials:
- label: Common errors
href: /reference/troubleshooting/common-errors/
cta:
label: Contact support
href: https://www.tigerdata.com/support/Any subset works. The component shows only what you provide.
Tutorials only:
learnMore:
tutorials:
- label: Next tutorial
href: /build/how-to/next/CTA only:
learnMore:
cta:
label: Try for free
href: https://console.cloud.tigerdata.com/signupPosts + CTA, no tutorials:
learnMore:
relatedPosts:
- label: The case for time-series databases
href: https://www.timescale.com/blog/time-series-case/
cta:
label: Read the whitepaper
href: https://www.timescale.com/resources/whitepaper/- Add or edit
learnMore:in a page's frontmatter. - Run
pnpm dev(orpnpm dev:localif you don't have a Stainless API key). - Open the page at
http://localhost:4321/<your-page-path>. - Resize the browser to at least 1024px wide. The card lives in the right rail, which collapses on smaller viewports.
- Toggle light/dark mode and confirm the card flips colors correctly.
- Click each link. Confirm internal links stay in-tab and external links open in a new tab.
If the card doesn't appear, jump to Troubleshooting.
- Viewport too narrow. The right rail is hidden below 1024px. Widen the window.
- Frontmatter key is misspelled or wrong-cased. It must be
learnMore(camelCase), notlearn_more,learnmore, orLearnMore. - All sections are empty. The card hides itself if
tutorials,relatedPosts, andctaare all absent or empty arrays. - YAML indentation is off. Each list item needs a
-and labels/hrefs need to be indented under the list item. When in doubt, copy a recipe above verbatim and edit. - Dev server cache. Astro occasionally caches frontmatter aggressively. Stop the dev server, then
rm -rf .astro node_modules/.vite node_modules/.astroand restartpnpm dev.
The content schema in src/content.config.ts strips unknown frontmatter keys. If you're seeing a schema error, you may be on a branch that pre-dates the schema merge. Pull the latest main.
The card uses its own styles (specificity 0,2,0) to override Starlight's default right-sidebar styles. If a link looks like it inherited the TOC styling, you may have nested an extra element inside the link or accidentally added a <p> in YAML. Strip it back to the recipe shape: each item is just { label, href }.
The card pulls from --button-secondary-* (default) and --stl-button-primary-* (hover) tokens defined in src/styles/tokens.css. If your local CSS overrides those, the button will follow. Don't override them per-page; they're meant to be theme-wide.
The card uses margin-top: auto inside a flex column. If you've added custom CSS on the page that breaks the .sl-container flex layout, the card will lose its bottom anchor. Don't add CSS that touches .sl-container or .right-sidebar-panel.
Browse these live examples to see the card in production context:
src/content/docs/build/examples/hybrid-search.mdx: full card (tutorials + related posts) added in PR #267.- Search the repo with
grep -rn "learnMore:" src/content/docs/to find every page currently using the card.
When you ship a new page using learnMore, you don't need to register it anywhere; it's auto-discovered through frontmatter.
| Concern | File |
|---|---|
| Frontmatter schema | src/content.config.ts → learnMoreSchema |
| Card component | src/components/LearnMore.astro |
| Rail mount point | src/components/PageSidebar.astro (overrides Starlight's default PageSidebar) |
| Registration | astro.config.ts → starlightCompat.components.PageSidebar |
- Every docs page runs through
PageSidebar.astro. It readsAstro.locals.starlightRoute.entry.data.learnMorefrom the page's frontmatter. - If that object is present and has at least one of
tutorials,relatedPosts, orcta, the component appends<LearnMore />after Starlight's default TOC inside the existing.sl-container. .sl-containeris styled as a flex column withmin-height: calc(100dvh - nav - 2rem). The card hasmargin-top: auto, which pushes it to the bottom of that column. Because Starlight's rail container is already viewport-sticky at the top, bottom-of-column ends up visually equal to bottom-of-viewport on any page taller than the viewport, with noposition: stickyneeded on the card itself.
Styles live in LearnMore.astro as an is:global block, with every selector chained through .learn-more .learn-more__X (specificity 0,2,0). This:
- Beats Starlight's right-sidebar defaults like
.right-sidebar-panel :where(a)(specificity0,1,0) without needing!importantor scope-breaking rules inPageSidebar.astro. - Keeps the card's type scale and colors owned by this one file: the rail's TOC CSS can't accidentally mutate the card, and vice versa.
The card uses local --lm-* CSS variables that cascade from project tokens (src/styles/tokens.css) with sensible fallbacks:
| Local token | Source token | Used for |
|---|---|---|
--lm-bg |
--step-card-bg |
Card background |
--lm-border |
--step-card-border |
Card border |
--lm-fg-strong |
--toc-title-active |
Title, section heads, icons |
--lm-fg-muted |
--tiger-fg-emphasized |
Link text and icons (chosen over --toc-title-inactive so 14px body copy clears WCAG AA at 4.5:1 in both themes) |
--lm-cta-bg / --lm-cta-fg / --lm-cta-border |
--button-secondary-* |
Outlined CTA (default state) |
--lm-cta-hover-bg / --lm-cta-hover-fg |
--stl-button-primary-* |
CTA on hover/focus |
Because all four source families flip correctly in dark mode, the card (and its button) Just Work when the user toggles the theme.
- Card, light, no CTA (3588-7875)
- Card, light, with CTA (3588-7948)
- Card, dark, no CTA (3588-7974)
- Card, dark, with CTA (3588-8047)
- CTA button (3245-9622)
- The graduation-cap and download-arrow icons are inlined SVGs with
currentColor, so they follow the surrounding text color through theme changes. Don't replace them with<img>or they'll stop flipping. - Changing styles inside the card's
<style is:global>block sometimes doesn't invalidate through Astro's HMR. If your tweak doesn't land after a save, kill the dev server, remove.astro/node_modules/.vite/node_modules/.astro, and restart withpnpm dev. - Don't add new
:global(.learn-more ...)rules toPageSidebar.astro. Anything LearnMore-specific belongs inLearnMore.astroso the two files don't mutate each other's cascade. - The right rail and this card both disappear on viewports under 1024px, which is by design. If you need related-content links to surface on mobile, put them in the page body itself (for example, using
RelatedContentCards).
- Starlight
PageSidebardocs - Original implementation: PR #220 (EDU-94)
- First usage: PR #267 (EDU-539)