Create a Custom CSS Snippet

The Custom CSS area is where you drop named, toggleable stylesheets that render in the head of every public page. Use it when you want to tweak brand colors, swap a font, tune a button radius, or layer a campaign override on top of your theme — without opening SG-Builder. Each snippet has a title, a status toggle, and a priority that controls cascade order. This guide walks from the Add New button to a live brand override rendering on your homepage.

A thin override layer

Your theme handles structural defaults — typography scale, spacing, button shapes, color tokens. Custom CSS lets you nudge any of those without rebuilding pages.

Renders straight to the page head, no cache

SGEN queries Active snippets on every public page request and emits each one inline. Flip a snippet Active and the next page load reflects it — browser cache is the only delay.

Deliberately narrow scope

Style rules only, no per-page targeting field, no minification or autoprefixing. SGEN passes your CSS straight through to the browser — you scope it by selector.

What this is for

Custom CSS is SGEN's global style-injection point. You write CSS once and it cascades over every public page until you turn it off. It sits at higher specificity than your theme defaults, so :root tokens, utility classes, and element-level overrides you put here win against the Appearance settings. It is not a page-content tool — page HTML belongs in SG-Builder.

Think of Custom CSS as a thin override layer above your theme. A single snippet can change the brand color across every button on every page in one save. A second snippet can layer a campaign-only treatment on top, then come off again when the campaign ends. Snippets are independent: you can have a dozen of them Active at once, and SGEN renders them in priority order.

The render path is plain. SGEN keeps the snippets in a database table, queries them on every public page request, and emits each Active row inside a <style> block in the document <head>. There is no client-side caching layer between you and the visitor. Browser cache may delay the change for a returning visitor; a hard reload sidesteps that.

The Custom CSS area is intentionally narrow in scope. It accepts only style rules, writes only to the head of every public page, and exposes no per-page targeting field in the form — you scope by selector instead. It does no minification, autoprefixing, or compilation. Pasting modern CSS — custom properties, nested rules where browsers support them, container queries, clamp() math — is fine; SGEN passes the source through to the browser, which does the work. If your audience includes older browsers, write your CSS with their support floor in mind.

Custom CSS is one of three style layers in SGEN, and each has a clear job. Theme Editor handles foundational tokens. SG-Builder's Additional CSS trait handles per-component scope. Custom CSS sits between them — site-wide reach, plain CSS rules, toggleable per snippet. The "How this connects" section below maps all three layers.

Good use cases

Eight working patterns, from a full brand refresh to a print-only stylesheet.

Example 1 — a brand refresh. Your marketing lead wants to roll out a seasonal warm-brown palette across every page — hero, buttons, headings — without re-saving every SG-Builder page. Create a new Custom CSS snippet titled Autumn Palette, paste the override block below, set priority 5, and flip Status to Active.

:root { --brand: #8b4513; --brand-hover: #6f3a10; --heading-font: "Playfair Display", serif;
}
h1, h2, h3 { font-family: var(--heading-font); letter-spacing: -0.01em;
}
.btn-primary { background: var(--brand); border-color: var(--brand); border-radius: 999px;
}

On the next public-page reload, every heading picks up the new serif font and every primary button switches to the brand brown — no SG-Builder edits needed. This pattern works because the :root declaration redefines the design-token variables your theme already reads; every component using var(--brand) updates at once. Roll the campaign back by flipping the snippet Inactive — the theme falls back to its own :root definitions.

Example 2 — hide a legacy widget on every page. An old email-signup sidebar widget is sitting on dozens of blog posts. Rather than opening each post, paste one Custom CSS rule and it's gone site-wide. Name the snippet Hide Legacy Signup Sidebar, priority 10, Active.

body .sidebar-email-signup-legacy { display: none;
}

No content is deleted — the widget stops rendering on visitors' screens. Set the snippet Inactive later and it reappears on the next page load. The same pattern works for any element you can target with a CSS selector: legacy promo bars, deprecated nav items, footer links you no longer want public.

Example 3 — a staging-only debug border. On a staging site, a developer wants every container that isn't aligned to the grid to jump out in red. Paste a quick debug stylesheet, leave it Inactive in production, and flip it Active on staging only.

/* Debug: highlight containers missing horizontal padding */
main .container:not([class*="px-"]) { outline: 2px dashed #dc2626; outline-offset: -2px;
}

Save it once, leave it Inactive on production, and turn it on whenever a layout looks wrong on staging. The dashed outline appears on any container missing the expected padding utility class.

Example 4 — page-scoped CSS by body class. You want to restyle only one landing page — narrower hero, warm cream background, smaller body text — without touching any other page. SGEN sets a body.page_id-<n> class on every public page, where <n> is the page ID. Use the ID, not the slug — a slug-based class disappears when the page is set as your homepage. Paste this snippet, priority 12, Active.

/* Landing page — page ID 47 */
body.page_id-47 .hero-section { background-color: #faf3e8; color: #3a2415; padding-block: 48px;
}
body.page_id-47 .hero-section h1 { max-width: 28ch; font-size: clamp(28px, 4vw, 44px);
}
body.page_id-47 main p { font-size: 15px; line-height: 1.7;
}

The rules only fire when body.page_id-47 is present in the DOM — every other page is untouched. Find the page ID in Pages — hover the row and the URL shows /sg-admin/pages/edit/<id>.

Example 5 — a campaign override stacked on top of brand. You already have a base Brand Tokens snippet at priority 1 (sets --brand, --accent, --heading-font). For a seasonal sale, marketing wants a temporary red-and-gold treatment without touching the base. Create a second snippet titled Campaign Override, priority 18 (so it loads after the base and wins on equal-specificity rules), Active for the campaign window. When the sale ends, flip it Inactive — the base snaps back, no edits to the base snippet.

/* Campaign Override — priority 18, Active for the sale window */
:root { --brand: #b91c1c; --accent: #fbbf24;
}
.btn-primary { background: var(--brand); box-shadow: 0 0 0 2px var(--accent);
}
.banner-promo { display: block; background: linear-gradient(90deg, #b91c1c 0%, #fbbf24 100%);
}

This is the canonical pattern: keep one stable base snippet at low priority, layer time-bound campaigns at higher priorities, toggle them on and off at status level. You never edit the base for campaigns — copy the campaign snippet, rename it, change the colors, save it Inactive until the launch date, and flip Active when the campaign opens.

Example 6 — hide an admin-only banner from public visitors. A yellow staging banner renders at the top of every page. You want it visible while logged in (so admins know they're on staging) but invisible to logged-out visitors. A signed-in browser carries an admin-session cookie that adds body.has-admin-session on the public page. Use the negation:

body:not(.has-admin-session) .staging-banner { display: none;
}

Visitors see a clean page; admins still get the yellow banner. If you don't have the has-admin-session body class wired up, this won't work — it needs cooperation from a Custom Code that reads the cookie. Coordinate with a developer before deploying this pattern.

Example 7 — restyle the ecommerce cart drawer. The cart drawer's default styling is fine, but the brand wants a warmer feel: cream background, brown accents, a touch more padding. Paste this snippet, priority 8, Active.

/* Cart drawer treatment — priority 8 */
.sg-cart-drawer { background-color: #faf3e8; border-left: 4px solid #8b4513; padding: 24px;
}
.sg-cart-drawer .cart-line-total { color: #8b4513; font-weight: 600;
}
.sg-cart-drawer .checkout-btn { background: #8b4513; border-radius: 999px; padding-block: 12px;
}

The drawer is rendered by SGEN's ecommerce module on every page that has an Add to Cart action — product pages, the cart page, anywhere a View Cart button appears. Site-wide CSS reaches all of those at once.

Example 8 — a print-only stylesheet for invoices and receipts. When a customer prints a receipt page, you want the layout to drop the navigation, hide the cookie banner, switch to black-on-white text, and tighten the line spacing. CSS media queries handle this without any extra UI. Paste this snippet, priority 6, Active.

@media print { header, nav, .cookie-banner, .footer-newsletter, .sg-cart-drawer { display: none; } body { color: #000; background: #fff; font-size: 11pt; line-height: 1.4; } .receipt-table { border: 1px solid #000; page-break-inside: avoid; }
}

The print stylesheet is invisible on screen — visitors never see it — and the browser switches to it the moment someone hits Print or saves to PDF. This is the cleanest place for print rules in SGEN; you don't have to touch any specific page's components.

What not to use this for

A few patterns cause silent failures or hard-to-diagnose problems. Avoid them.

Scripts
No JavaScript or HTML here

The save handler strips anything that looks like a tag. Paste a <script> or a <div> and it is silently removed — your snippet saves as empty. Use Custom → Codes for HTML and scripts.

Style tags
Skip the wrapper

Don't wrap your CSS in <style> tags. The form expects raw CSS. Wrapper tags are stripped on save, and you risk losing inner content if the strip pass bites.

Content tricks
Escape angle brackets in content

A rule like body::before { content: "<b>hi</b>"; } gets its tag stripped on save, breaking the output. If you need literal angle brackets in content:, escape them as Unicode (\003C, \003E).

Scope
Always scope per-page rules

There's no per-row Targets field — every Active snippet renders on every page. For one-page tweaks, prefix every selector with body.page_id-<n> or use SG-Builder's Additional CSS trait on the component.

Size
Keep snippets small

The server accepts large pastes without complaint, but your homepage will bloat. If a single snippet is over a few kilobytes, split it — one for tokens, one for the campaign — so you can toggle them individually.

Secrets
No secrets in CSS

Whatever you paste renders verbatim inside a style block in the public page source. Anyone who views source can read it. If you're tempted, that content probably belongs in Custom Codes with environment-specific scoping, or in the page itself.

Cascade
Prefer specificity over the priority flag

Leaning on a cascade-priority hack works once but is a tax you pay forever — the next override has to also use it. Increase selector specificity instead (prefix with body). Reserve the hack for genuinely overriding an inline style or a third-party library that already uses it.

Status
Use the toggle, not the URL

The Status field is a controlled Active/Inactive toggle. Manipulating the form to send other values may persist oddly in storage but leaves the snippet invisible on the public site and confusing in the list.

Sort order
The list sorts by date, not priority

The list orders by created-date by default. Priority controls render order on the public page, not display order in admin. Sort the list by the Priority column to see render order at a glance.

Roles
No per-role visibility

There's no per-user or per-role scoping on Custom CSS — every Active snippet renders for every visitor. For conditional styles based on session state, use the body-class pattern from Example 6, with a Custom Code adding the class on render.

Trash
Trash isn't a long-term archive

Soft-deleted snippets stay in Trash for 30 days, then disappear. For a historical archive (last year's holiday treatment, an A/B test you might revisit), keep the snippet Inactive instead of trashing it.

Sessions
One editor at a time

Two admins editing the same snippet at the same time will overwrite each other's changes — the last save wins. Agree on who is editing, or duplicate the snippet and merge by hand.

How this connects to other features

Custom CSS is one of three style-injection layers in SGEN. Knowing which layer to use saves time and avoids overlap.

Custom Codes

The place for third-party scripts, stylesheet links, font references, tag managers, cookie banners, and any non-CSS HTML. Custom CSS is styles only; Custom Codes is everything else. Both render globally and both have a status toggle.

Appearance → Theme Editor

For brand colors, typography choices, button radius, and the foundational design tokens the whole site reads from. Custom CSS is one specificity level higher, so anything you write here overrides Theme Editor on a per-rule basis. Use Theme Editor when the change is permanent and brand-foundational; use Custom CSS for a tactical override or campaign-time treatment.

SG-Builder → Additional CSS trait

Every component on every SG-Builder page has an Additional CSS trait. Rules pasted there are scoped to that component instance only and ship inline with the page. That's the right tool for a one-off, one-page tweak — Custom CSS is the wrong tool for that scope because it travels everywhere, not with the page.

A common pattern in production sites: brand-foundational tokens live in Theme Editor, site-wide treatments and seasonal campaigns live in Custom CSS (with priorities to control cascade), per-component fine-tuning lives in SG-Builder's Additional CSS trait, and operational scripts (analytics, consent banners, font loaders) live in Custom Codes. When you're not sure which layer to use, ask: how broad is the change, and how permanent is it?

Heads up Custom CSS keeps no version history — only the current value is stored. Before a major edit to a brand-critical stylesheet, save a copy of the current CSS somewhere outside SGEN (a text file, a snippet manager, your team's wiki).

Before you start

Signed in as an SGEN admin

You need Custom CSS access. If Custom → CSS isn't visible in the left navigation, ask your site owner.

CSS ready to paste, no wrapper

Have your raw CSS rules ready — no <style> wrapper around them.

Know Active vs Inactive at save time

Decide whether you want the snippet live immediately (Active) or saved as a draft (Inactive).

Page ID and priority plan, if relevant

For a page-scoped snippet, know the target page's ID (open its edit URL — the number at the end of /sg-admin/pages/edit/<id>). For a campaign stacked on a base, have a priority plan: base layer low, campaign layer higher.

A way to verify, and a backup

Keep a private or incognito browser window ready to check the public site without cached output. Keep a backup of the CSS you're pasting somewhere outside SGEN, in case a save corrupts the snippet through the tag-stripping rules.

Steps

1
Open the Add New form

Click + Add New on the list toolbar. SGEN opens the create form — a two-column layout, title and CSS editor on the left, status and priority on the right.

2
Fill in the fields

Title — a descriptive name for your reference, never shown on the public site. Defaults prefill with "My Custom CSS" — change it before saving.

CSS snippet — paste raw CSS into the syntax-highlighted editor. <style> wrappers are removed on save; paste rules without them.

Priority — any integer from 1 to 20. Lower numbers render first, higher numbers render last and therefore override. Give a base-brand snippet priority 1 and a campaign snippet a higher number so the campaign wins.

Status — toggle Active to render on visitors' pages immediately, or leave it off to save as a draft.

3
Click Create Custom CSS

On success you see a green confirmation banner and the page moves to the edit view for your new snippet. If validation fails — most often a blank or under-2-character title — you see a red error banner and the form re-renders with your CSS preserved. Fix the title and submit again; your CSS is never lost on a validation failure.

4
Verify on the public site

Open your public homepage in a new tab, or hard-reload with Ctrl+Shift+R to bypass the cache. If the snippet is Active, your styles should apply immediately. Right-click the page and choose View page source, then search for part of your CSS — you'll find it wrapped in a <style> block inside <head>, alongside any other Active snippets. A private or incognito window is more reliable than a hard reload, since it carries no prior session or cached state.

5
Edit an existing snippet

Click the row title in the list — SGEN opens the same two-column form, prefilled. Change any field, click Update Custom CSS. A safe pattern when iterating: flip Status to Inactive before editing, save, make your changes, save again, then flip back to Active — this avoids broadcasting a half-finished rule to live visitors.

6
Toggle a snippet between Active and Inactive

Open the snippet for edit, flip the Active checkbox, click Update. The list reflects the new status immediately. Inactive snippets keep their CSS in storage; they just stop rendering. This is the recommended way to disable a campaign override at the end of a window — don't delete it, keep it Inactive so you can reuse it next time.

7
Adjust priority for cascade order

If two Active snippets target the same selector and the wrong one is winning, priority is your knob. Open the lower-priority snippet, raise its number, save. SGEN renders in ascending priority — priority 5 emits before priority 10, so priority 10 overrides at equal specificity. Two snippets at the same priority fall back to creation order — the older row emits first and loses. Keep priorities distinct when order matters.

8
Move a snippet to Trash

Hover a row and click Trash. A confirm dialog asks you to confirm the move before it takes effect. The snippet stops rendering and moves to the Trash tab, with the CSS preserved for 30 days. If you trashed one by mistake, open the Trash tab, click the row, and choose Restore — it returns to whatever status it had before.

What success looks like

After clicking Create Custom CSS and reloading your public site:

List shows Active

The list at Custom → CSS shows your new snippet with a green Active status badge.

Homepage reflects the styles

Colors, fonts, button radii, whatever your CSS specified, applied on the public page.

View source confirms it

Searching for any selector from your snippet finds it inside a <style> block in <head>, alongside any other Active snippets.

A success banner confirms the save

A confirmation banner reports the snippet was created and lists the fields saved — title, priority, status, and CSS content.

DevTools shows the winning rule

Browser DevTools (F12, then the Elements pane) shows your rules applied, and the Styles pane lists your snippet as the source of the winning rule.

If your snippet is one of several, the cascade order matches the Priority field: priority 1 loads first, priority 20 loads last, and the last-loaded rule wins on equal-specificity selectors. When in doubt, sort the list by the Priority column to see the exact emit order.

What to do if it does not work

Common issues and their fixes.

Cache
Saved but nothing changed on the public site

Check that Status is Active — Inactive snippets are stored but don't render. Then hard-reload with Ctrl+Shift+R. If that doesn't help, open a private or incognito window, which bypasses every cache layer at once.

Sanitizer
CSS looks different in storage than what you pasted

Check for tag-like strings. The save handler strips anything between < and >, including patterns inside content properties or attribute selectors, and any <style> wrapper. Replace literal angle brackets with escaped Unicode (\003C, \003E).

Cascade
Priority isn't working the way you expect

CSS cascade is priority AND specificity. Same selector — the later-priority rule wins. Different selectors — the more specific one wins regardless of priority. Increase specificity by prefixing with body rather than reaching for a priority hack.

A bare selector matched too much
Selector

A bare element selector like h1 { color: red; } colors every h1 on the site, including ones you didn't intend. Tighten the selector to a parent container or a class. Flip the suspect snippet Inactive, reload, confirm the issue disappears, then edit the selector.

Typo
Snippet shows up but the styles aren't applied

Usually a selector typo or an upstream priority conflict from another snippet. Open DevTools, inspect the element, and check the Computed and Styles panes to see whether your rule is matched, overridden, or never selected.

Defaults
Unexpected title or status on a row

That row was saved without changing the default. Open it for edit and change the title. Default titles are placeholders, not ghost text — a fresh form saves as "My Custom CSS" if you don't replace the value. Same for Status: the form defaults to Inactive on first open.

Redirect
Landed somewhere unexpected after save

If you arrived via a third-party link with a redirect parameter, the form may follow it on success. Always reach the form via the left navigation rather than external links. If your admin ever lands on a non-SGEN URL after saving, treat that as a security signal and report it to your platform team.

Priority
Public page is using older styles

Check whether multiple Active snippets target the same selector — the highest priority and latest creation date wins. Sort the list by Priority to see the order, then use the stacking pattern from Example 5 to layer a campaign on top of a base.

Missing row
Can't find a snippet after editing it

Check the Trash tab. A snippet moved to Trash leaves the All and Active tabs and only shows under Trash. Restore it from there.

Silent fail
Success banner appeared but nothing changed in storage

Reload the list — if the row's timestamp doesn't reflect your save, it quietly failed at the validation layer. The most common cause is empty CSS combined with <style> wrapper stripping. Open the row, paste valid CSS without wrappers, save again.

Undo
Deleted a row by mistake

Open the Trash tab — soft-deleted rows live there, not permanently gone. Click the row, choose Restore, and it returns to the list. Hard delete only happens from the Trash tab, with a confirmation.

Conflict
Two snippets cancel each other out

This happens when two rules target the same property on the same selector at the same specificity. Decide which should win, then either raise the winner's priority or rewrite the loser's selector to a different specificity. A common cause: a base snippet and a campaign snippet both setting background on the same class.

Filter
List is missing rows you expected

Check the active filter pill — Active view hides Inactive and Trashed rows. Click All Custom CSS to see everything except Trash. Also clear any leftover search term from a previous session.

Cache
Long wait for the public page to reflect a change

SGEN doesn't cache Custom CSS server-side — your update is live on the next request. The wait is browser cache; a hard reload or incognito window resolves it. If you run a CDN in front of a custom domain, you may need to purge the CDN's cache too.

Browser support
Modern CSS not applying for some visitors

Container queries, :has(), nested rules, and certain clamp() patterns landed later in some browsers than others. SGEN passes your CSS through unchanged — no autoprefixing or polyfilling — so legacy support is on you. Write a widely-supported fallback and layer modern syntax inside an @supports block.

What to do next

For multi-snippet sites, sketch a short priority map — each snippet's title, priority, and purpose — in a text file or team wiki; it pays for itself the first time cascade order breaks. Agree on a naming convention with your team (<area>-<purpose>-<version>, for example brand-tokens-v2) so titles stay meaningful as the list grows.