How to Add a Custom HTML Section in Shopify

Add custom HTML to a Shopify page: the built-in Custom Liquid section, a reusable HTML section with a schema, escaping pitfalls, and update-safety.

5 min readUpdated

Part of our guide to Shopify Custom Sections: The Complete Guide.

Sometimes you just need to drop a block of HTML onto a page — an embed, a table, a formatted notice, a snippet of markup from another tool. Shopify gives you two routes for this, and picking the right one saves a lot of frustration: the built-in Custom Liquid section for a one-off, or a small custom HTML section with a schema when you want the same block reused and editable. This guide walks through both, plus the escaping and script pitfalls that trip people up.

This assumes an Online Store 2.0 theme (Dawn or later), where both options are available.

Option 1 — The built-in Custom Liquid section (no code file)

Most modern themes ship a Custom Liquid section. It is the quickest way to add HTML without touching theme files.

In the theme editor (Online Store → Themes → Customize), open the page you want, click Add section, and choose Custom Liquid. A single text box appears; paste your HTML (or Liquid) into it and Save. Anything you put in the box renders exactly where the section sits.

<div class="shipping-notice">
  <strong>Free shipping</strong> on orders over $50.
  Delivered in 2–4 business days.
</div>

This is genuinely the fastest path for a small, one-off block. Its limits are worth knowing:

  • There is no structure — one big field, no separate heading/image/link settings, so a non-technical merchant editing it later is editing raw markup.
  • One unclosed tag can break the whole page, because the box accepts anything.
  • Reusing the same block on several pages means pasting it into each one separately.

If any of those bite, move to a proper section.

Option 2 — A reusable custom HTML section (with a schema)

When you want the same HTML block on multiple pages, or want a merchant to edit its text safely, build it as a real section. It is a small .liquid file in sections/ that pairs your HTML with a {% schema %} exposing just the fields you want editable.

Create sections/html-notice.liquid:

<div class="html-notice">
  <h2 class="html-notice__title">{{ section.settings.title }}</h2>
  <div class="html-notice__body">{{ section.settings.body }}</div>
</div>

{% schema %}
{
  "name": "HTML notice",
  "tag": "section",
  "settings": [
    {
      "type": "text",
      "id": "title",
      "label": "Title",
      "default": "Shipping information"
    },
    {
      "type": "richtext",
      "id": "body",
      "label": "Body",
      "default": "<p>Free shipping on orders over $50.</p>"
    }
  ],
  "presets": [
    { "name": "HTML notice" }
  ]
}
{% endschema %}

Now the block appears in Add section, a merchant edits the title and body in normal form fields, and you can place it on any page. The full pattern — markup, schema, and styling — is in How to create a custom section in Shopify.

Raw HTML vs. escaped HTML — the pitfall

When you output a value in Liquid, the field type decides whether HTML is rendered or shown as text. This catches people constantly:

  • richtext and html settings output rendered HTML — <p> becomes a paragraph.
  • A plain text setting is escaped — if a merchant types <p>Hi</p>, the page literally shows the tags as text.

If you have raw HTML in a variable and genuinely need it rendered (and you trust the source), Shopify does not auto-escape output from richtext/html fields. Do not try to "un-escape" untrusted input — that is how you invite broken markup or worse onto the page. For merchant-authored rich content, use a richtext setting and let Shopify handle it.

A note on <script> tags and embeds

Pasting third-party embed code — a widget, a form, an analytics snippet — into a Custom Liquid box often looks like it works, but scripts added this way can behave unpredictably: they may not re-run when the theme editor re-renders the section, and some embeds expect to run in the document <head>. For anything involving <script>, treat it as a distinct problem rather than raw HTML, and follow the safety and load-order guidance in Custom Liquid and JavaScript, safely.

Keep static markup (tables, notices, formatted text) in the HTML section; handle scripts deliberately.

Styling the HTML block

Scope your CSS to the block's class so it does not leak into the rest of the theme. The safest place is a {% stylesheet %} block in the same section file:

{% stylesheet %}
.html-notice {
  padding: 1.5rem;
  border: 1px solid #e3e3e3;
  border-radius: 0.5rem;
}
.html-notice__title {
  font-size: 1.25rem;
  margin: 0 0 0.5rem;
}
{% endstylesheet %}

For the trade-offs between an inline stylesheet, an assets/ file, and the theme's color settings, see How to add custom CSS to a section.

Keeping HTML sections on a theme update

Both routes above store your work in theme files — the Custom Liquid box saves into the template JSON, and a custom section file lives in sections/. That is the normal setup, with one honest caveat: when you install a new version of the theme or switch themes, Shopify publishes a fresh copy of the theme's files, and hand-added HTML or a custom section file that is not carried over is lost, along with its settings.

Two ways to protect it:

  1. Track your custom files and pasted blocks and re-apply them after each update, per Update your theme without losing customizations.
  2. Render the block from an app via a Theme App Extension, so it appears in the editor but is not part of the theme's files.

If the HTML block is something you rely on, SectionGuard renders it from the app rather than your theme — so it survives theme updates and swaps with the same in-editor editing merchants already expect.