@v4/ghost-content
The editorial content-block components: article headers, rich text, promos, embeds and carousels, composed over ghost-core.
Overview
@v4/ghost-content is the editorial content-block package — the components
that make up an article body and the content-led pages around it: article and
listing headers, rich-text wells, pull quotes, stats blocks, promos, social and
gallery embeds, and the content carousels. It carries 72 components (the
newest is header-block-feature) plus a small set of shared internal layouts
under src/components/_internal/ (article-card-by-format, article-header,
article-page, carousel-block, listing-header, listing-page) that several
public components are built over.
It is a sibling of @v4/ghost-core, built exactly the same way — typed
vanilla-extract themes, colour-set axis, 100% binding coverage — and it composes
ghost-core rather than re-implementing anything: a content block that needs a
button, badge or link imports the real one from @v4/ghost-core. Content
components bind g.components.content.* contract paths (never raw
tokens.components.content.*) so Euro League's overrides flow through.
Built from the ELB fork
In this repo the source of truth for every component is ELB – Web –
Content (9iz5GeR9syO68cmPr1ppE1), ELB's fork of Ghost – Content 2.0
(RHCx7G92nx50KjNK6QshhU). The fork preserves the upstream node ids, so a
bridge that still names the Ghost file resolves every id perfectly while
measuring the wrong design — re-verify a bridge's fileKey, not just that its
ids resolve. Why, and what follows for a component, is on
Building against ELB's Figma forks.
Measured on 6 Nov 2026 from each component's *.figma.json: 59 bridges name
ELB – Web – Content, 12 still name Ghost – Content, and one, clips-block (the
frame of the WSC Stories row), names ELB – Web – EXT (Yqy0zItrtL4UptOVW54wVg).
node packages/token-parser/scripts/check-bridges.mjs is the offline gate.
For the representative-component tour with Storybook deep links, see the
sibling-packages catalogue. For how these
blocks are assembled into pages and mounted by the app, see
@v4/content-app.
Entry points
| Import | Contents |
|---|---|
@v4/ghost-content |
The 72 content components and their prop types / mock props |
@v4/ghost-content/init.css |
Owner-keyed side-effect stylesheet emitting the package's --ph__* CSS variables |
@v4/ghost-content/components/<name> (15) |
One component on its own — see below |
The 15 per-component subpaths are accordion-block, block-scroller,
download-block, gateway-carousel, promo-block-article-promo,
promo-block-floating-image, promo-block-full-image, promo-block-simple,
promo-block-supporting-image, promo-carousel, promo-countdown-banner,
stats-block, tabbed-carousel, table-block and text-image-block (17
export keys in all, with . and ./init.css). They exist for import cost: the
less common blocks are loaded with next/dynamic only by a page that renders
them (packages/content-app/src/lib/lazy-blocks.tsx). Imported from the barrel,
every page with any block carried all of them, about 63 KB gzip of script
(25 Oct 2026).
How it is consumed
@v4/content-app composes these blocks into the CONTENT domain's page bodies
(news article, listing, and so on). The app mounts those via generated shims.
@v4/ghost-basketball, @v4/basketball-app and @v4/code-of-conduct compose
content components too.
The package registers its themes through createPackageTheme with an explicit
OWN_THEMES list in its init.css.ts. In the app, apps/web/src/theme/tokens.css.ts
emits Euro League's values for ghost-core and ghost-content together on every
page (see @v4/ghost-core) — the theming model is
shared across the four Ghost packages in this repo: ghost-core, -content,
-video and -basketball. See
Component system and
Theming and colour sets.