Reusable Content Sections
Build flexible, merchant-configurable content sections that work across multiple pages and templates in your Shopify theme.
Content sections are the building blocks of modern Shopify themes. Creating reusable sections that work across templates saves development time and empowers merchants to build diverse pages.
The Philosophy of Reusable Sections
Good content sections share these traits:
- Flexible: Work on any page type
- Configurable: Settings for layout, style, spacing
- Block-based: Add, remove, reorder content
- Accessible: Semantic HTML and proper ARIA
- Responsive: Look great on all devices
Rich Text Section
A versatile section for any text content:
{# sections/rich-text.liquid #}
{%- style -%} .section-{{ section.id }} { padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px; {%- if section.settings.background_color != 'rgba(0,0,0,0)' -%} background-color: {{ section.settings.background_color }}; {%- endif -%} }
.section-{{ section.id }} .rich-text__content { text-align: {{ section.settings.text_alignment }}; max-width: {{ section.settings.content_width }}px; }{%- endstyle -%}
<section class="rich-text section-{{ section.id }}"> <div class="container"> <div class="rich-text__content"> {%- for block in section.blocks -%} {%- case block.type -%} {%- when 'heading' -%} <{{ block.settings.heading_tag }} class="rich-text__heading" {{ block.shopify_attributes }} > {{ block.settings.heading }} </{{ block.settings.heading_tag }}>
{%- when 'text' -%} <div class="rich-text__text rte" {{ block.shopify_attributes }}> {{ block.settings.text }} </div>
{%- when 'button' -%} {%- if block.settings.link != blank -%} <a href="{{ block.settings.link }}" class="button button--{{ block.settings.button_style }}" {{ block.shopify_attributes }} > {{ block.settings.label }} </a> {%- endif -%}
{%- when 'spacer' -%} <div class="rich-text__spacer" style="height: {{ block.settings.height }}px;" {{ block.shopify_attributes }} ></div> {%- endcase -%} {%- endfor -%} </div> </div></section>
{% schema %}{ "name": "Rich Text", "tag": "section", "class": "rich-text-section", "settings": [ { "type": "select", "id": "text_alignment", "label": "Text alignment", "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" }, { "value": "right", "label": "Right" } ], "default": "center" }, { "type": "range", "id": "content_width", "label": "Content width", "min": 400, "max": 1000, "step": 50, "default": 700, "unit": "px" }, { "type": "color", "id": "background_color", "label": "Background color" }, { "type": "range", "id": "padding_top", "label": "Padding top", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" }, { "type": "range", "id": "padding_bottom", "label": "Padding bottom", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" } ], "blocks": [ { "type": "heading", "name": "Heading", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Your Heading Here" }, { "type": "select", "id": "heading_tag", "label": "Heading level", "options": [ { "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" }, { "value": "h3", "label": "H3" }, { "value": "h4", "label": "H4" } ], "default": "h2", "info": "Use H1 only once per page" } ] }, { "type": "text", "name": "Text", "settings": [ { "type": "richtext", "id": "text", "label": "Text content", "default": "<p>Add your text content here.</p>" } ] }, { "type": "button", "name": "Button", "settings": [ { "type": "text", "id": "label", "label": "Button label", "default": "Learn More" }, { "type": "url", "id": "link", "label": "Button link" }, { "type": "select", "id": "button_style", "label": "Button style", "options": [ { "value": "primary", "label": "Primary" }, { "value": "secondary", "label": "Secondary" }, { "value": "outline", "label": "Outline" } ], "default": "primary" } ] }, { "type": "spacer", "name": "Spacer", "settings": [ { "type": "range", "id": "height", "label": "Height", "min": 10, "max": 100, "step": 10, "default": 30, "unit": "px" } ] } ], "presets": [ { "name": "Rich Text", "blocks": [ { "type": "heading" }, { "type": "text" } ] } ]}{% endschema %}Multi-Column Section
Flexible columns for features, team, or any grid content:
{# sections/multi-column.liquid #}
{%- style -%} .section-{{ section.id }} { padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px; }
.section-{{ section.id }} .multi-column__grid { --columns: {{ section.settings.columns }}; }{%- endstyle -%}
<section class="multi-column section-{{ section.id }}"> <div class="container"> {%- if section.settings.heading != blank -%} <h2 class="multi-column__heading">{{ section.settings.heading }}</h2> {%- endif -%}
{%- if section.blocks.size > 0 -%} <div class="multi-column__grid"> {%- for block in section.blocks -%} <div class="multi-column__item" {{ block.shopify_attributes }}> {%- if block.settings.image != blank -%} <div class="multi-column__image"> {%- if block.settings.image_style == 'circle' -%} {{ block.settings.image | image_url: width: 300 | image_tag: loading: 'lazy', class: 'multi-column__img multi-column__img--circle' }} {%- else -%} {{ block.settings.image | image_url: width: 600 | image_tag: loading: 'lazy', class: 'multi-column__img' }} {%- endif -%} </div> {%- endif -%}
{%- if block.settings.heading != blank -%} <h3 class="multi-column__item-heading">{{ block.settings.heading }}</h3> {%- endif -%}
{%- if block.settings.text != blank -%} <div class="multi-column__item-text rte"> {{ block.settings.text }} </div> {%- endif -%}
{%- if block.settings.link != blank and block.settings.link_label != blank -%} <a href="{{ block.settings.link }}" class="multi-column__link"> {{ block.settings.link_label }} </a> {%- endif -%} </div> {%- endfor -%} </div> {%- endif -%} </div></section>
{% schema %}{ "name": "Multi-column", "settings": [ { "type": "text", "id": "heading", "label": "Heading" }, { "type": "range", "id": "columns", "label": "Columns on desktop", "min": 2, "max": 6, "default": 3 }, { "type": "range", "id": "padding_top", "label": "Padding top", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" }, { "type": "range", "id": "padding_bottom", "label": "Padding bottom", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" } ], "blocks": [ { "type": "column", "name": "Column", "settings": [ { "type": "image_picker", "id": "image", "label": "Image" }, { "type": "select", "id": "image_style", "label": "Image style", "options": [ { "value": "default", "label": "Default" }, { "value": "circle", "label": "Circle" } ], "default": "default" }, { "type": "text", "id": "heading", "label": "Heading", "default": "Column Title" }, { "type": "richtext", "id": "text", "label": "Text", "default": "<p>Describe this column content.</p>" }, { "type": "url", "id": "link", "label": "Link" }, { "type": "text", "id": "link_label", "label": "Link label", "default": "Learn more" } ] } ], "presets": [ { "name": "Multi-column", "blocks": [ { "type": "column" }, { "type": "column" }, { "type": "column" } ] } ]}{% endschema %}Image with Text Section
Classic two-column layout:
{# sections/image-with-text.liquid #}
{%- style -%} .section-{{ section.id }} { padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px; }{%- endstyle -%}
<section class="image-with-text section-{{ section.id }}"> <div class="container"> <div class="image-with-text__grid image-with-text__grid--{{ section.settings.layout }}"> <div class="image-with-text__media"> {%- if section.settings.image != blank -%} {{ section.settings.image | image_url: width: 900 | image_tag: loading: 'lazy', class: 'image-with-text__img' }} {%- else -%} {{ 'image' | placeholder_svg_tag: 'image-with-text__placeholder' }} {%- endif -%} </div>
<div class="image-with-text__content"> {%- if section.settings.subheading != blank -%} <span class="image-with-text__subheading">{{ section.settings.subheading }}</span> {%- endif -%}
{%- if section.settings.heading != blank -%} <h2 class="image-with-text__heading">{{ section.settings.heading }}</h2> {%- endif -%}
{%- if section.settings.text != blank -%} <div class="image-with-text__text rte"> {{ section.settings.text }} </div> {%- endif -%}
{%- if section.settings.button_link != blank and section.settings.button_label != blank -%} <a href="{{ section.settings.button_link }}" class="button button--primary"> {{ section.settings.button_label }} </a> {%- endif -%} </div> </div> </div></section>
{% schema %}{ "name": "Image with Text", "settings": [ { "type": "image_picker", "id": "image", "label": "Image" }, { "type": "select", "id": "layout", "label": "Image position", "options": [ { "value": "image-first", "label": "Image left" }, { "value": "text-first", "label": "Image right" } ], "default": "image-first" }, { "type": "text", "id": "subheading", "label": "Subheading" }, { "type": "text", "id": "heading", "label": "Heading", "default": "Image with Text" }, { "type": "richtext", "id": "text", "label": "Text", "default": "<p>Pair text with an image to give customers insight into your brand.</p>" }, { "type": "text", "id": "button_label", "label": "Button label" }, { "type": "url", "id": "button_link", "label": "Button link" }, { "type": "range", "id": "padding_top", "label": "Padding top", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" }, { "type": "range", "id": "padding_bottom", "label": "Padding bottom", "min": 0, "max": 100, "step": 10, "default": 60, "unit": "px" } ], "presets": [ { "name": "Image with Text" } ]}{% endschema %}Testimonials Section
Social proof with block-based testimonials:
{# sections/testimonials.liquid #}
<section class="testimonials section-{{ section.id }}"> <div class="container"> {%- if section.settings.heading != blank -%} <h2 class="testimonials__heading">{{ section.settings.heading }}</h2> {%- endif -%}
{%- if section.blocks.size > 0 -%} <div class="testimonials__grid testimonials__grid--{{ section.settings.layout }}"> {%- for block in section.blocks -%} <blockquote class="testimonial" {{ block.shopify_attributes }}> {%- if section.settings.show_stars -%} <div class="testimonial__stars" aria-label="{{ block.settings.rating }} out of 5 stars"> {%- for i in (1..5) -%} <span class="testimonial__star{% if i <= block.settings.rating %} testimonial__star--filled{% endif %}">★</span> {%- endfor -%} </div> {%- endif -%}
<p class="testimonial__quote">{{ block.settings.quote }}</p>
<footer class="testimonial__footer"> {%- if block.settings.avatar != blank -%} <div class="testimonial__avatar"> {{ block.settings.avatar | image_url: width: 80 | image_tag }} </div> {%- endif -%}
<div class="testimonial__author"> <cite class="testimonial__name">{{ block.settings.author }}</cite> {%- if block.settings.title != blank -%} <span class="testimonial__title">{{ block.settings.title }}</span> {%- endif -%} </div> </footer> </blockquote> {%- endfor -%} </div> {%- endif -%} </div></section>
{% schema %}{ "name": "Testimonials", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "What Our Customers Say" }, { "type": "select", "id": "layout", "label": "Layout", "options": [ { "value": "single", "label": "Single column" }, { "value": "grid", "label": "Grid" }, { "value": "carousel", "label": "Carousel" } ], "default": "grid" }, { "type": "checkbox", "id": "show_stars", "label": "Show star ratings", "default": true } ], "blocks": [ { "type": "testimonial", "name": "Testimonial", "settings": [ { "type": "textarea", "id": "quote", "label": "Quote", "default": "This product changed my life! Highly recommended." }, { "type": "text", "id": "author", "label": "Author name", "default": "Jane Doe" }, { "type": "text", "id": "title", "label": "Author title", "default": "Verified Customer" }, { "type": "image_picker", "id": "avatar", "label": "Avatar" }, { "type": "range", "id": "rating", "label": "Star rating", "min": 1, "max": 5, "default": 5 } ] } ], "presets": [ { "name": "Testimonials", "blocks": [ { "type": "testimonial" }, { "type": "testimonial" }, { "type": "testimonial" } ] } ]}{% endschema %}Call to Action Section
{# sections/call-to-action.liquid #}
{%- style -%} .section-{{ section.id }} { --cta-bg: {{ section.settings.background_color }}; --cta-text: {{ section.settings.text_color }}; padding: {{ section.settings.padding }}px 0; }{%- endstyle -%}
<section class="cta section-{{ section.id }}"> <div class="container"> <div class="cta__content"> {%- if section.settings.heading != blank -%} <h2 class="cta__heading">{{ section.settings.heading }}</h2> {%- endif -%}
{%- if section.settings.text != blank -%} <p class="cta__text">{{ section.settings.text }}</p> {%- endif -%}
<div class="cta__buttons"> {%- if section.settings.primary_link != blank -%} <a href="{{ section.settings.primary_link }}" class="button button--primary-light"> {{ section.settings.primary_label | default: 'Get Started' }} </a> {%- endif -%}
{%- if section.settings.secondary_link != blank -%} <a href="{{ section.settings.secondary_link }}" class="button button--outline-light"> {{ section.settings.secondary_label | default: 'Learn More' }} </a> {%- endif -%} </div> </div> </div></section>
{% schema %}{ "name": "Call to Action", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Ready to Get Started?" }, { "type": "textarea", "id": "text", "label": "Text", "default": "Join thousands of happy customers today." }, { "type": "text", "id": "primary_label", "label": "Primary button label", "default": "Get Started" }, { "type": "url", "id": "primary_link", "label": "Primary button link" }, { "type": "text", "id": "secondary_label", "label": "Secondary button label" }, { "type": "url", "id": "secondary_link", "label": "Secondary button link" }, { "type": "color", "id": "background_color", "label": "Background color", "default": "#1a1a1a" }, { "type": "color", "id": "text_color", "label": "Text color", "default": "#ffffff" }, { "type": "range", "id": "padding", "label": "Section padding", "min": 20, "max": 100, "step": 10, "default": 60, "unit": "px" } ], "presets": [ { "name": "Call to Action" } ]}{% endschema %}Section CSS Patterns
/* Multi-column */.multi-column__grid { display: grid; gap: var(--spacing-lg); grid-template-columns: repeat(1, 1fr);}
@media (min-width: 768px) { .multi-column__grid { grid-template-columns: repeat(var(--columns, 3), 1fr); }}
.multi-column__item { text-align: center;}
.multi-column__img--circle { border-radius: 50%; aspect-ratio: 1; object-fit: cover;}
/* Image with text */.image-with-text__grid { display: grid; gap: var(--spacing-xl); align-items: center;}
@media (min-width: 768px) { .image-with-text__grid { grid-template-columns: 1fr 1fr; }
.image-with-text__grid--text-first .image-with-text__media { order: 2; }}
.image-with-text__subheading { display: block; font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--color-primary); margin-bottom: var(--spacing-sm);}
/* Testimonials */.testimonials__grid { display: grid; gap: var(--spacing-lg);}
.testimonials__grid--grid { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));}
.testimonial { background: var(--color-background-subtle); padding: var(--spacing-lg); border-radius: var(--border-radius-lg); margin: 0;}
.testimonial__stars { margin-bottom: var(--spacing-md);}
.testimonial__star { color: #d1d5db;}
.testimonial__star--filled { color: #fbbf24;}
.testimonial__quote { font-size: 1.125rem; line-height: 1.6; margin-bottom: var(--spacing-md);}
.testimonial__footer { display: flex; align-items: center; gap: var(--spacing-sm);}
.testimonial__avatar img { width: 48px; height: 48px; border-radius: 50%; object-fit: cover;}
.testimonial__name { font-style: normal; font-weight: 600; display: block;}
.testimonial__title { font-size: 0.875rem; color: var(--color-text-light);}
/* Call to Action */.cta { background: var(--cta-bg); color: var(--cta-text);}
.cta__content { text-align: center; max-width: 700px; margin: 0 auto;}
.cta__heading { font-size: clamp(1.5rem, 4vw, 2.5rem); margin-bottom: var(--spacing-md);}
.cta__buttons { display: flex; gap: var(--spacing-md); justify-content: center; flex-wrap: wrap; margin-top: var(--spacing-lg);}Building a Section Library
Shopify requires all sections in a flat sections/ directory (no subfolders). Use naming prefixes to organize by purpose:
sections/├── content-rich-text.liquid├── content-multi-column.liquid├── content-image-with-text.liquid├── content-testimonials.liquid├── content-call-to-action.liquid├── media-image-banner.liquid├── media-video.liquid├── media-slideshow.liquid├── product-featured.liquid├── product-recommendations.liquid├── collection-featured.liquid└── collection-list.liquidThis naming convention keeps related sections grouped alphabetically in your editor and makes the section type clear at a glance.
Practice Exercise
Create reusable sections for:
- A team section with member blocks
- A features/benefits grid with icons
- A logo cloud (partner/client logos)
Test each section on:
- Homepage
- About page
- Landing page template
Key Takeaways
- Block-based design enables merchant flexibility
- Settings for spacing/colors adapt to different contexts
- Scoped CSS with
section-{{ section.id }} - Presets show sample content in theme editor
- Responsive grids with CSS custom properties
- Semantic HTML for accessibility
- RTE class for rich text content styling
What’s Next?
The next lesson covers Blog and Article Templates for building a content-rich blog.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...