Part of our guide to Shopify Custom Sections: The Complete Guide.
Styling a section is where most theme breakage starts. A rule written a little too
broadly — button { ... }, .container { ... } — leaks out of your section and
quietly changes buttons and containers on every other page. This guide covers the
three places you can put a section's CSS, how to scope it so it stays contained,
and how to lean on the theme's own color settings instead of hard-coding values.
It assumes you already have a section file. If you don't, start with
how to create a custom section in Shopify
and come back — the section referenced below is the feature-banner.liquid from
that guide.
Option 1 — A {% stylesheet %} block in the section file
The simplest place for a section's CSS is a {% stylesheet %} tag inside the
section's own .liquid file. Shopify pulls the contents of every section's
stylesheet block into a single, minified theme stylesheet, and only loads it when
the section is on the page. Everything stays in one file, so the markup and its
styles travel together.
{% stylesheet %}
.feature-banner {
padding: 3rem 1.5rem;
background: #f4f4f2;
}
.feature-banner__heading {
font-size: 1.75rem;
margin: 0 0 0.5rem;
}
{% endstylesheet %}
Two rules keep this out of trouble:
- Scope every selector to the section's own class. Prefix with
.feature-banner(or a BEM-style.feature-banner__heading) so nothing matches elements outside the section. - Liquid does not run inside
{% stylesheet %}. The block is treated as static CSS, so you cannot write{{ section.settings.color }}in it. For merchant-set values, use the inline-style approach in Option 3.
This is the right default for most sections: self-contained, only loaded when needed, and impossible to forget when you copy the file elsewhere.
Option 2 — A file in assets/
When the CSS is long, shared across several sections, or you simply prefer separate
files, put it in the theme's assets/ folder and link it from the section.
Create assets/feature-banner.css, then load it at the top of the section file:
{{ 'feature-banner.css' | asset_url | stylesheet_tag }}
<section class="feature-banner">
...
</section>
asset_url resolves the file to its full CDN path, and stylesheet_tag wraps it
in a proper <link> element. Because the tag sits inside the section, the
stylesheet is requested wherever the section renders.
The trade-off versus Option 1: an assets/ file is a separate HTTP request rather
than part of the bundled theme stylesheet, and it is a second file you have to
remember to carry over when you move the section. For a large, reusable stylesheet
that is a fair price; for a small section it usually is not.
Option 3 — Merchant-controlled colors from the schema
Hard-coding #008060 means every store that uses your section gets that exact
green, and a merchant can never change it. To make color a setting, add a
color (or color_scheme) field to the schema and apply it with an inline style
where Liquid does run — the markup.
Add the setting:
{% schema %}
{
"name": "Feature banner",
"settings": [
{
"type": "color",
"id": "bg_color",
"label": "Background color",
"default": "#f4f4f2"
}
]
}
{% endschema %}
Then apply it in the markup with a scoped inline style. Wrapping it in a
{% style %} block keyed to the section's unique id keeps the rule tied to this
one instance:
{% style %}
#shopify-section-{{ section.id }} .feature-banner {
background: {{ section.settings.bg_color }};
}
{% endstyle %}
<section class="feature-banner">
...
</section>
section.id is unique per placement, and Shopify wraps every section in a
#shopify-section-{{ section.id }} element automatically — so this rule can never
match another section on the page, even a second copy of the same one.
Better still: reuse the theme's color scheme
The most maintainable option is not to introduce a new color at all, but to inherit
the theme's. Online Store 2.0 themes expose a color_scheme setting type and CSS
custom properties (Dawn uses rgb(var(--color-foreground)),
rgb(var(--color-background)), and similar). Reference those and your section
re-brands itself whenever the merchant changes the theme's colors:
{% stylesheet %}
.feature-banner {
color: rgb(var(--color-foreground));
background: rgb(var(--color-background));
}
{% endstylesheet %}
The exact variable names vary by theme, so check the theme's config/settings_data.json
or its base stylesheet before relying on them.
The one thing that actually breaks themes
Almost every "my section broke the whole store" problem traces back to an unscoped
selector. Styling a bare tag or a generic class name — h2 { ... }, .button,
.grid — matches those elements everywhere, not just inside your section. Keep
three habits and it stays contained:
- Give the section one root class (
.feature-banner) and scope every rule under it. - For per-instance rules, key them to
#shopify-section-{{ section.id }}. - Never style an element type or a theme utility class directly.
Keeping the CSS through a theme update
Whichever option you choose, the CSS lives in your theme files — a
{% stylesheet %} block, an assets/ file, or a schema setting inside the section.
When you update or switch themes, Shopify publishes a fresh copy of the theme and
those files are not carried over, so the styling goes with the section it belonged
to. The disciplined way to handle that is in
update your theme without losing customizations;
the structural way is to render the section — and its CSS — from an app instead, so
a theme update never touches it.
If a section is one you rely on long-term, SectionGuard renders it and its styles from the app rather than your theme, so both survive every theme update and swap while keeping the same in-editor color settings merchants expect.