Advanced

Code injection

Restyle any part of Enova by pasting a few lines of CSS into Ghost's Code injection box. Every major section and component has a stable, named handle, so your tweaks keep working after theme updates.

Want to nudge a colour, hide a widget, or resize your logo without forking the theme? Enova gives every major part of the page a stable handle you can target with a few lines of CSS. You paste that CSS once into Ghost's Code Injection and it sticks, even when you update the theme.

No theme editing required

Everything on this page is done through Ghost Admin → Settings → Code injection. You don't edit theme files, and you don't rebuild anything. Code Injection survives theme updates, which is exactly why it's the safe place for custom CSS. (Editing the theme files directly is not safe: your changes are erased the next time you upload a new enova.zip.)

The naming convention

Enova labels its building blocks with a small, predictable set of HTML attributes — a naming convention you can reason about. Once you know the four words below, you can usually guess the hook for something instead of looking it up:

  • data-region marks a big structural area, like the site header, the article body, or a sidebar. There's usually one of each per page.
  • data-component marks a reusable unit that can appear many times, like a post card, a sidebar widget, or the pagination bar.
  • data-variant tells apart flavours of the same component — for example a post card rendered as a grid tile versus a list row, or which sidebar-widget you're looking at.
  • data-part marks a piece inside a component or region — the title, kicker, excerpt, meta (byline/date), image, or read-time. These names are the same everywhere, so the headline of any story preview is [data-part="title"], whether it's an <h1> or a <p>. A few parts live outside story previews: logo (the brand logo image), wordmark (the brand link / text site title), author, date, and cover (an archive cover image).
AttributeMeansHow manyExample values
data-regiona structural area~one per pagesite-header, masthead, start-sidebar, end-sidebar, post-body, site-footer, comments
data-componenta repeating unitmanypost-card, sidebar-widget, story-link, pagination, newsletter-cta, newsletter-card
data-varianta flavour of its hostpairedgrid, list, featured, email, cta, bio, recent, related
data-parta piece inside the hostmanytitle, kicker, excerpt, meta, image, read-time, logo, wordmark, author, date, cover

You compose these by nesting — region, then component (with its variant), then part — and you can scope the whole thing to one page type or one layout mode (shown in the next sections).

To target any of them, use an attribute selector in CSS:

<style>
  /* A structural region */
  [data-region="site-footer"] { font-size: 0.95rem; }

  /* Every post card on the site */
  [data-component="post-card"] { /* ... */ }

  /* Only the list-style post card */
  [data-component="post-card"][data-variant="list"] { /* ... */ }

  /* The headline inside any post card, whatever element it uses */
  [data-component="post-card"] [data-part="title"] { /* ... */ }
</style>

What not to target

Enova uses other data-* attributes internally — they wire up JavaScript or belong to Ghost itself — and those are not part of this styling API. Only the four above (data-region, data-component, data-variant, data-part) are a promise. Leave the rest alone, because they can change or disappear in any update:

  • Theme machinery (drives Enova's own scripts): data-navigation-style, data-hide-left-sidebar, data-hide-right-sidebar, data-sidebar-nav, data-nav-pending, data-header-nav, data-sticky-fit-height, data-footer-grid, data-footer-nav-target, data-toc-mount, data-grid-layout-class, data-newsletter-archive, data-year-rail, data-enova-social, and the like.
  • Page state on <html>: data-color-scheme. For dark-mode tweaks, use the .dark class instead (shown later). You may read the layout-state hooks to scope a rule — see the next section — but never override them.
  • Ghost & libraries (owned by Ghost, not the theme): data-portal, data-members-*, data-ghost-search, data-lazy-comments-*.

A quick test: if the name reads like the four-word grammar — an area, a unit, a flavour, or a piece — it's fair game. If it reads like a wiring label (-nav, -mount, -target, portal), don't style against it.

Don't fight the sidebars

Enova's left and right sidebars collapse, slide, and stick under JavaScript control. The styling hooks are deliberately placed on inner wrappers ([data-region="start-sidebar"], [data-region="end-sidebar"]) that are safe to style — but do not set width, position, transform, top, or height on a sidebar region or its widgets. Those properties are how the open/close animation and the sticky behaviour work; overriding them can freeze a sidebar open or break the scroll-pinning. Style the contents (colours, fonts, spacing, borders, hiding a widget) freely.

Scope a change to a layout mode or state

This is unique to Enova. Because the sidebars and navigation can be configured and toggled, Enova exposes a few read-only hooks on the <html> element. You may use them in a selector to limit when a rule applies — but never set or override them.

<style>
  /* Only when navigation is in Top bar mode */
  [data-navigation-style="top-bar"] [data-region="site-header"] { /* ... */ }

  /* Only when the reader has collapsed both sidebars (wider content) */
  .sidebars-closed [data-region="post-feed"] { gap: 2.5rem; }

  /* Only when the left sidebar is collapsed */
  .start-sidebar-closed [data-region="post-body"] { /* ... */ }

  /* Only when the right sidebar is collapsed */
  .end-sidebar-closed [data-region="post-body"] { /* ... */ }
</style>
SelectorTrue when
[data-navigation-style="sidebar"] / [data-navigation-style="top-bar"]The admin's chosen navigation layout
.nav-top-barTop bar navigation is active (mirrors the above)
.start-sidebar-closedThe left sidebar is collapsed on desktop
.end-sidebar-closedThe right sidebar is collapsed on desktop
.sidebars-closedBoth desktop sidebars are collapsed
.darkDark mode is active (see Dark mode)

Scope a change to one kind of page

Ghost adds a class to the <body> of every page that tells you what kind of page it is — home-template, post-template, page-template, tag-template, author-template, and error-template (plus paged on pages 2, 3, and so on). Combine that with a hook to scope a change to just one place:

<style>
  /* The hero headline, but only on the homepage */
  .home-template [data-region="hero"] [data-part="title"] { /* ... */ }

  /* Pagination, but only on tag archives */
  .tag-template [data-component="pagination"] { /* ... */ }
</style>

Reach the elements inside a region

The hooks mark the containers. To style something inside one, add a selector after the hook. For the parts of a story preview, prefer the data-part hook over a bare element selector — the heading level varies between layouts, but the part name doesn't:

<style>
  /* The title of every sidebar widget's story links */
  [data-region="end-sidebar"] [data-component="story-link"] [data-part="title"] { /* ... */ }

  /* The byline row on a post */
  [data-region="post-meta"] { /* ... */ }
</style>

Hook reference

Every handle Enova ships, grouped by where it lives. Compose them as region → component[variant] → part.

Site-wide chrome

HookWhat it is
[data-region="site-header"]The sticky top header bar
[data-region="masthead"]The logo + menu-toggle cluster (left of the header)
[data-part="wordmark"]The brand link wrapping the logo or site title
[data-part="logo"]The brand logo image (and the text fallback when there's no logo)
[data-component="auth-links"]The Sign in / Join cluster in the header
[data-region="primary-nav"]The horizontal nav (Top bar navigation mode only)
[data-region="site-footer"]The footer
[data-component="footer-brand"]The footer brand block (logo, description, social)
[data-region="footer-nav"]The footer navigation columns
[data-region="footer-legal"]The copyright / colophon row
[data-component="social-links"]A social-icon cluster
[data-component="reading-progress"]The scroll-to-top progress button (posts)
HookWhat it is
[data-region="start-sidebar"]The left navigation sidebar (inner content — safe to style)
[data-region="sidebar-nav"]The navigation block inside the left sidebar
[data-region="end-sidebar"]The right sidebar (inner content — safe to style)
[data-component="sidebar-widget"]Any card in the right sidebar (see variants below)
[data-component="sidebar-widget"][data-variant="about"]The publication "about" card
…[data-variant="featured"]The Featured posts widget
…[data-variant="recent"]The Recent posts widget
…[data-variant="popular-tags"]The Popular Tags widget
…[data-variant="top-authors"]The Top Authors widget
…[data-variant="newsletter"]The newsletter signup widget
…[data-variant="recommended"]The Recommendations widget
…[data-variant="related"]The Related posts widget (posts only)
…[data-variant="house-ad"]The house ad card (renders a published page slugged house-ad)
…[data-variant="sponsors"]The sponsors logo grid (renders a published page slugged sponsors)
[data-component="table-of-contents"][data-variant="sidebar"]The sticky table of contents in the right sidebar

Homepage & feeds

HookWhat it is
[data-region="hero"]The homepage hero band
[data-region="hero"][data-variant="featured"]Featured-posts carousel hero
…[data-variant="email"]Email-subscription hero
…[data-variant="cta"]Call-to-action hero
…[data-variant="bio"]Author-bio hero
[data-region="home-feed"]The tabbed feed wrapper on the homepage
[data-region="post-feed"]The post grid/list itself

Posts & pages

HookWhat it is
[data-region="post"] / [data-region="page"]The article root
[data-region="post-header"] / [data-region="page-header"]The title block above the content
[data-region="post-meta"]The author / date / read-time / comments bar
[data-region="feature-image"]The post or page feature image
[data-region="post-body"]The article body (also covers pages)
[data-region="comments"]The comments section
[data-component="table-of-contents"][data-variant="inline"]The collapsible in-article table of contents
[data-component="member-cta"][data-variant="signup"]The members-only paywall (signed-out)
[data-component="member-cta"][data-variant="upgrade"]The members-only paywall (signed-in, needs upgrade)
[data-component="post-nav-link"][data-variant="prev"] / [data-variant="next"]Previous / next post links
[data-component="newsletter-cta"]A newsletter signup form (footer + sidebar)

Story previews & their parts

These repeat across cards, rails, and lists. The part names are uniform, so one rule reaches them everywhere.

HookWhat it is
[data-component="post-card"]A feed post card ([data-variant="grid"] or [data-variant="list"])
[data-component="story-link"]A compact text/thumbnail row (sidebar widgets, recommendations)
[data-component="recommendations"]The recommendations list
[data-part="title"]The headline of any preview
[data-part="kicker"]The primary-tag label above a headline
[data-part="excerpt"]The summary text
[data-part="meta"]The byline / date row
[data-part="image"]The preview's image
[data-part="author"]The author name link
[data-part="date"]The published date
[data-part="read-time"]The "N min read" label

Archives & errors

HookWhat it is
[data-region="archive-header"][data-variant="tag"]The tag-archive header
[data-region="archive-header"][data-variant="author"]The author-archive header
[data-part="cover"]The archive cover image
[data-region="error"][data-variant="404"]The 404 page body

Enova has no breadcrumb bar

Unlike some themes, Enova doesn't render a visible breadcrumb trail (it ships breadcrumbs as invisible SEO metadata only), so there's no breadcrumb hook to style.

Newsletter archive

HookWhat it is
[data-region="newsletter-archive"]The whole archive page wrapper
[data-region="archive-hero"]The archive hero
[data-component="archive-ledger"]The hero's "ledger" stat card
[data-region="archive-feed"]The list of issues
[data-region="archive-empty"]The empty / coming-soon state
[data-component="year-rail"]The floating year jump-rail
[data-component="newsletter-card"]An issue card — variants list, magazine, compact, timeline, timeline-compact

Common snippets

Copy a block, tweak the numbers, paste it into Settings → Code injection → Site Header.

Header, logo & branding

Hiding things

Typography & spacing

Dark mode

Troubleshooting

  • My rule isn't applying. Make sure you pasted it inside a <style>…</style> block in Code injection, not as bare CSS. Check the attribute value matches exactly (kebab-case, e.g. popular-tags, not Popular Tags).
  • It works, then breaks after I toggle a sidebar. You're probably setting width, position, transform, top, or height on a sidebar region. Style the contents instead, and use the layout-state selectors if you need the rule to apply only in a certain state.
  • A built-in style is winning. Add more of the hooks to raise specificity — e.g. [data-region="end-sidebar"] [data-component="sidebar-widget"][data-variant="recent"] [data-part="title"] — rather than reaching for !important.

These handles are a promise

The four attributes — data-region, data-component, data-variant, data-part — are a stable, documented API. We treat renaming or removing one as a breaking change and call it out in the changelog. Everything else in the markup (utility classes, JavaScript wiring attributes) can change in any update, so build your Code Injection against the hooks above and it'll keep working.