Jillur Rahman

Jillur Rahman

Front-End Developer

Back to Blog
Development11 min read

How to Build Custom Shopify Sections That Your Theme Can't Do Out of the Box

Shopify's section system is powerful — but every theme has limits on what's possible through the editor alone. A developer can build custom sections that give you full design control, dynamic data, and features no app can match.

ShopifyLiquidCustom SectionsTheme DevelopmentConversion
Cover image for: How to Build Custom Shopify Sections That Your Theme Can't Do Out of the Box

Every Shopify theme ships with a set of pre-built sections — hero banners, featured collections, testimonials, image-with-text. These are designed to cover the most common use cases for most stores.

Your store is not most stores.

When you need a section that your theme doesn't provide — a product comparison table, a before-and-after slider, a multi-step quiz that recommends products, a countdown timer tied to real inventory — you have two options: install an app that adds it (with the performance and cost implications that brings), or have a developer build it as a native Shopify section.

Custom sections built by a developer load faster, look exactly like your brand, and give your content team full editing control in the Shopify theme editor without touching code. Here's what that looks like in practice.


How Shopify Sections Actually Work

A Shopify section is a Liquid template file in your theme's sections/ directory. It has two parts:

The template — HTML and Liquid that renders the section's content on the page.

The schema — A JSON block at the bottom of the file that defines what settings appear in the theme editor. Settings can be text fields, dropdowns, image selectors, color pickers, product/collection references, checkboxes, and more.

{% comment %} sections/custom-hero.liquid {% endcomment %}
 
<section
  class="custom-hero"
  style="background-color: {{ section.settings.bg_color }};"
>
  <div class="hero-content">
    <h1>{{ section.settings.heading }}</h1>
    <p>{{ section.settings.subheading }}</p>
    <a href="{{ section.settings.button_url }}" class="btn">
      {{ section.settings.button_text }}
    </a>
  </div>
  {% if section.settings.hero_image %}
    <img
      src="{{ section.settings.hero_image | image_url: width: 1200 }}"
      alt="{{ section.settings.hero_image.alt | escape }}"
      width="1200"
      loading="eager"
    >
  {% endif %}
</section>
 
{% schema %}
{
  "name": "Custom Hero",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading" },
    { "type": "textarea", "id": "subheading", "label": "Subheading" },
    { "type": "url", "id": "button_url", "label": "Button URL" },
    { "type": "text", "id": "button_text", "label": "Button text", "default": "Shop Now" },
    { "type": "image_picker", "id": "hero_image", "label": "Hero image" },
    { "type": "color", "id": "bg_color", "label": "Background color", "default": "#ffffff" }
  ],
  "presets": [{ "name": "Custom Hero" }]
}
{% endschema %}

Once this file exists in the theme, your content team can add it to any page in the theme editor, fill in the settings, and see a live preview — no code changes needed.


Custom Section 1: Dynamic Product Showcase With Filters

The default Shopify collection page shows products in a grid. What if you want a feature section that shows "Best Sellers in a specific category" or "New arrivals this week" pulled dynamically from your catalog?

A developer can build a section that:

  • Takes a collection handle as a setting
  • Sorts by best-selling, newest, or custom sort order
  • Shows a limited number of products (4, 6, 8, etc.)
  • Displays variant swatches and real-time availability
  • Links to collection with correct filters pre-applied
{% assign feature_collection = collections[section.settings.collection] %}
{% assign sort_by = section.settings.sort_by | default: 'best-selling' %}
{% assign product_limit = section.settings.product_count | default: 4 %}
 
{% assign sorted_products = feature_collection.products
  | sort: sort_by
  | limit: product_limit %}
 
<section class="dynamic-showcase">
  <div class="showcase-header">
    <h2>{{ section.settings.heading }}</h2>
    <a href="{{ feature_collection.url }}">View all</a>
  </div>
 
  <div class="product-grid" data-columns="{{ section.settings.columns }}">
    {% for product in sorted_products %}
      {% render 'product-card', product: product %}
    {% endfor %}
  </div>
</section>
 
{% schema %}
{
  "name": "Dynamic Product Showcase",
  "settings": [
    { "type": "text", "id": "heading", "label": "Section heading" },
    { "type": "collection", "id": "collection", "label": "Collection to feature" },
    {
      "type": "select",
      "id": "sort_by",
      "label": "Sort products by",
      "options": [
        { "value": "best-selling", "label": "Best selling" },
        { "value": "created-descending", "label": "Newest" },
        { "value": "price-ascending", "label": "Price: Low to High" }
      ],
      "default": "best-selling"
    },
    {
      "type": "range",
      "id": "product_count",
      "label": "Number of products",
      "min": 2, "max": 12, "step": 2, "default": 4
    }
  ],
  "presets": [{ "name": "Dynamic Product Showcase" }]
}
{% endschema %}

Your marketing team can change which collection is featured, how many products show, and the sort order — directly in the editor, no developer needed after it's built.


Custom Section 2: Product Comparison Table

If you sell products in different tiers — starter, professional, enterprise, or good/better/best — a comparison table is one of the highest-converting sections you can have on a collection or landing page.

No standard Shopify theme includes a dynamic comparison table. Apps provide them but charge monthly. A custom section does it better:

{% comment %} sections/comparison-table.liquid {% endcomment %}
{% assign compare_products = section.blocks
  | where: "type", "product_column" %}
 
<section class="comparison-table">
  <h2>{{ section.settings.heading }}</h2>
 
  <div class="table-scroll">
    <table>
      <thead>
        <tr>
          <th>Features</th>
          {% for block in compare_products %}
            {% assign prod = all_products[block.settings.product] %}
            <th>
              <img src="{{ prod.featured_image | image_url: width: 200 }}" alt="{{ prod.title }}">
              <span>{{ prod.title }}</span>
              <span class="price">{{ prod.price | money }}</span>
              <a href="{{ prod.url }}" class="btn">Buy Now</a>
            </th>
          {% endfor %}
        </tr>
      </thead>
      <tbody>
        {% for feature_block in section.blocks %}
          {% if feature_block.type == "feature_row" %}
            <tr>
              <td>{{ feature_block.settings.feature_name }}</td>
              {% for col in compare_products %}
                <td>{{ col.settings['feature_' | append: forloop.index] }}</td>
              {% endfor %}
            </tr>
          {% endif %}
        {% endfor %}
      </tbody>
    </table>
  </div>
</section>
 
{% schema %}
{
  "name": "Comparison Table",
  "max_blocks": 20,
  "settings": [
    { "type": "text", "id": "heading", "label": "Section heading" }
  ],
  "blocks": [
    {
      "type": "product_column",
      "name": "Product",
      "settings": [
        { "type": "product", "id": "product", "label": "Product" }
      ]
    },
    {
      "type": "feature_row",
      "name": "Feature row",
      "settings": [
        { "type": "text", "id": "feature_name", "label": "Feature name" },
        { "type": "text", "id": "feature_1", "label": "Column 1 value" },
        { "type": "text", "id": "feature_2", "label": "Column 2 value" },
        { "type": "text", "id": "feature_3", "label": "Column 3 value" }
      ]
    }
  ],
  "presets": [{ "name": "Comparison Table" }]
}
{% endschema %}

The content team adds products and feature rows in the editor. The table updates visually in real time. No app subscription, no performance overhead.


Custom Section 3: Before/After Image Slider

For stores selling anything with visible results — cleaning products, skincare, landscaping, home renovation — a before/after slider is compelling social proof that a static image can't replicate.

This requires a small amount of JavaScript to handle the drag interaction:

<div
  class="before-after-slider"
  data-before="{{ section.settings.before_image | image_url: width: 1200 }}"
  data-after="{{ section.settings.after_image | image_url: width: 1200 }}"
>
  <div class="after-image">
    <img src="{{ section.settings.after_image | image_url: width: 1200 }}"
         alt="{{ section.settings.after_label }}">
    <span class="label after-label">{{ section.settings.after_label }}</span>
  </div>
  <div class="before-image">
    <img src="{{ section.settings.before_image | image_url: width: 1200 }}"
         alt="{{ section.settings.before_label }}">
    <span class="label before-label">{{ section.settings.before_label }}</span>
  </div>
  <div class="slider-handle" role="slider" aria-label="Before/after comparison">
    <div class="handle-line"></div>
    <div class="handle-icon">⟺</div>
  </div>
</div>

The JavaScript implementation uses pointer events for cross-device compatibility (mouse, touch, and stylus). 60fps drag interaction with CSS clip-path for smooth reveal. About 80 lines of code total — no library, no app.


What Custom Sections Replace

When I build custom sections for a store, they typically replace:

FeatureApp cost/monthCustom section (one-time)
Before/after slider$8–$154 hours developer time
Product comparison table$15–$251 day developer time
Interactive FAQ accordion$7–$122 hours developer time
Social proof ticker$9–$183 hours developer time
Countdown timer$8–$152 hours developer time
Video section with custom layout$10–$203 hours developer time

The break-even on custom development versus app subscriptions for these features is typically 2–4 months. After that, you're ahead every month — and your store loads faster because there are fewer external scripts.


The Right Sections to Build Custom

Not everything is worth custom development. A complex email marketing integration, a subscription billing system, a product review platform — these are genuinely complex services with ongoing operational costs. Keep the apps for these.

But any UI feature that: lives on your storefront, your content team needs to edit regularly, and costs money monthly as an app — is worth evaluating for custom development.

If you have sections you wish your theme had, or features you're paying app subscriptions for that could be built natively, I can scope what each one would take and whether the development investment makes sense for your store.

Tags:ShopifyLiquidCustom SectionsTheme DevelopmentConversion
Jillur Rahman — author

Jillur Rahman

Open to work

Front-End Developer & Shopify Theme Specialist — building fast, conversion-focused web experiences for agencies and brands worldwide.

All articles