Code injection
Restyle any part of Enova with a few lines of CSS in Ghost's Code injection. Learn the stable data-* hooks, what's safe to target, and how to scope rules.
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 in this guide 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.)
This guide comes in three parts — this page teaches the system, and two companion pages do the looking-up and the copy-pasting:
Hook reference
Every handle Enova ships, in lookup tables grouped by where it lives on the page.
Common snippets
Ready-to-paste CSS for the most-requested tweaks — starting with resizing your logo.
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-regionmarks a big structural area, like the site header, the article body, or a sidebar. There's usually one of each per page.data-componentmarks a reusable unit that can appear many times, like a post card, a sidebar widget, or the pagination bar.data-varianttells apart flavours of the same component — for example a post card rendered as agridtile versus alistrow, or whichsidebar-widgetyou're looking at.data-partmarks a piece inside a component or region — thetitle,kicker,excerpt,meta(byline/date),image, orread-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,comments-count, andcover(an archive cover image).
| Attribute | Means | How many | Example values |
|---|---|---|---|
data-region | a structural area | ~one per page | site-header, masthead, start-sidebar, end-sidebar, post-body, site-footer, comments |
data-component | a repeating unit | many | post-card, sidebar-widget, story-link, pagination, newsletter-cta, newsletter-card |
data-variant | a flavour of its host | paired | grid, list, featured, email, cta, bio, recent, related |
data-part | a piece inside the host | many | title, 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.darkclass instead (see Common snippets). 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>| Selector | True when |
|---|---|
[data-navigation-style="sidebar"] / [data-navigation-style="top-bar"] | The admin's chosen navigation layout |
.nav-top-bar | Top bar navigation is active (mirrors the above) |
.start-sidebar-closed | The left sidebar is collapsed on desktop |
.end-sidebar-closed | The right sidebar is collapsed on desktop |
.sidebars-closed | Both desktop sidebars are collapsed |
.dark | Dark mode is active |
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>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, notPopular Tags). - It works, then breaks after I toggle a sidebar. You're probably setting
width,position,transform,top, orheighton 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 documented hooks and it'll keep working.
Publication Language
Enova ships 62 languages with full RTL support. Set your publication language in Ghost Admin and the theme translates itself.
Hook reference
Every data-region, data-component, data-variant, and data-part hook Enova ships, in lookup tables — header, sidebars, posts, archives, and errors.