Part of our guide to Shopify Custom Sections: The Complete Guide.
This guide walks through building a Shopify custom section from an empty file to a live, editable block on your storefront. You will end up with a "Feature banner" section — a heading, a paragraph, and a button — that a merchant can configure entirely from the theme editor. It assumes an Online Store 2.0 theme (Dawn or any theme published after mid-2021).
Before you start, work on an unpublished copy of your theme. In your Shopify admin, go to Online Store → Themes, open the ⋯ menu on your live theme, and choose Duplicate. Edit the duplicate so a mistake never touches live traffic, then publish when you are happy.
What you need
- Access to your theme's code — either the browser code editor (Themes → ⋯ → Edit code) or the Shopify CLI with a local checkout of the theme.
- An Online Store 2.0 theme, so the section can be added and reordered in the editor rather than hard-coded into a template.
Step 1 — Create the section file
Sections live in the theme's sections/ folder. Create a new file there named
feature-banner.liquid. The file name (without the extension) is the section's
type — it is how templates and the editor refer to it, so keep it lowercase
and hyphenated.
In the code editor: open sections, click Add a new section, and name it
feature-banner. Shopify creates sections/feature-banner.liquid with a starter
{% schema %} you will replace in the next steps.
Step 2 — Write the markup
At the top of the file, add the HTML for the section. Read every editable value
from section.settings.<id> — those ids are defined by the schema you add in
Step 3. Wrapping the markup in a class scoped to the section keeps its styles from
leaking into the rest of the page.
<section class="feature-banner">
<div class="feature-banner__inner">
<h2 class="feature-banner__heading">{{ section.settings.heading }}</h2>
<p class="feature-banner__text">{{ section.settings.body }}</p>
{% if section.settings.button_label != blank %}
<a
class="feature-banner__button"
href="{{ section.settings.button_link }}"
>
{{ section.settings.button_label }}
</a>
{% endif %}
</div>
</section>
Two details that matter:
- The
{% if section.settings.button_label != blank %}guard means the button only renders when a merchant actually fills it in — an empty setting never leaves a stray, linkless button on the page. - Everything reads from
section.settings, so nothing is hard-coded. That is what makes the section configurable in the editor.
Step 3 — Add the schema
The {% schema %} block is JSON that names the section, declares its settings,
and — through presets — lets it appear in the theme editor's "Add section"
menu. Add this at the bottom of the file:
{% schema %}
{
"name": "Feature banner",
"tag": "section",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Free shipping over $50"
},
{
"type": "richtext",
"id": "body",
"label": "Body text",
"default": "<p>Delivered in 2–4 business days.</p>"
},
{
"type": "text",
"id": "button_label",
"label": "Button label"
},
{
"type": "url",
"id": "button_link",
"label": "Button link"
}
],
"presets": [
{ "name": "Feature banner" }
]
}
{% endschema %}
Key points:
- Each
idin the schema is what you read assection.settings.<id>in the markup — they must match exactly. presetsis what lets the section be added from the editor. Without it, the section exists but cannot be inserted onto a page.- The schema must be valid JSON. A trailing comma or an unquoted key will make the section fail to load, so paste it whole rather than typing it by hand.
Step 4 — Style the section
Add the CSS. The safest place is a {% stylesheet %} block inside the same
section file — Shopify collects it into the theme's stylesheet, and scoping every
rule to the .feature-banner class keeps it from colliding with the theme.
{% stylesheet %}
.feature-banner {
padding: 3rem 1.5rem;
background: #f4f4f2;
}
.feature-banner__inner {
max-width: 60rem;
margin: 0 auto;
text-align: center;
}
.feature-banner__heading {
font-size: 1.75rem;
margin: 0 0 0.5rem;
}
.feature-banner__button {
display: inline-block;
margin-top: 1rem;
padding: 0.75rem 1.5rem;
border-radius: 0.375rem;
background: #008060;
color: #fff;
text-decoration: none;
}
{% endstylesheet %}
If you would rather keep the CSS separate, or need it to react to the theme's own
color scheme, see
How to add custom CSS to a section
for the trade-offs between a {% stylesheet %} block, an assets/ file, and the
theme editor's built-in color settings.
Step 5 — Add it in the theme editor
Save the file, then open the theme editor: Online Store → Themes → Customize.
On any template, click Add section, find Feature banner in the list (it
appears because of the presets entry), and add it. Fill in the heading, body,
and button, drag it to where you want it, and Save.
That is the full loop: a merchant can now configure this section with no code, and place it on any template. To reuse the same section on other pages, see How to add a section to a page.
A note on tokens and metafields
Two upgrades make a section feel native and data-driven:
- Design tokens. Rather than hard-coding
#008060, pull from the theme's own color scheme so the section matches the store automatically. Dawn-based themes expose CSS custom properties likergb(var(--color-foreground))and provide acolor_schemesetting type you can add to the schema. Referencing those means a merchant who re-brands the store updates your section for free. - Metafields. When a section should show store or product data — a spec table,
a care guide, a badge — read it from a metafield instead of a text setting,
e.g.
{{ product.metafields.custom.care_guide }}. The content then lives with the product and stays in sync everywhere the section is used. Define the metafield under Settings → Custom data first.
Keep this section update-safe
Everything above writes the section into your theme files. That is the normal,
documented way to build a section — but be clear-eyed about the trade-off: when
you install a new version of the theme or switch themes, Shopify publishes a fresh
copy of the theme's files and your feature-banner.liquid is not carried
over. The section, and any settings merchants configured, can disappear.
Two ways to protect the work:
- Keep a disciplined workflow — track every custom file and re-apply it after each theme update. The method is in Update your theme without losing customizations.
- Render the section from an app instead of a theme file, via a Theme App Extension, so no theme update or swap can touch it.
If the section is something you rely on long-term, SectionGuard renders it from the app rather than your theme files — so it survives every theme update and swap, with the same in-editor configuration merchants already expect.