Demonstrate Flex Inside Page.
View this pattern on the live demo site
Flexible page: skips breadcrumbs when the first block is a banner, then renders flex sections.
{% comment %}
Highly configurable page with flexible content blocks. This layout allows for the maximum flexibility in a single template, but may result in more work for the editor to configure everything the way they want.
When possible, it is usually preferable to create specific page templates for different layouts/configurations, but this allows a strong fallback for pages where the layout is not easy to determine in advance or where it may change frequently.
When the first flex section is a banner, breadcrumbs are skipped so the hero can sit flush under the site nav.
{% endcomment -%}
{%- include "/_header.liquid" -%}
{%- var flex_opens_with_banner = false -%}
{%- if entity.flex_sections.is_valid -%}
{%- var first_flex = entity.flex_sections | first -%}
{%- if first_flex.type.value == 'banner' and first_flex.hide_section.on == false -%}
{%- set flex_opens_with_banner = true -%}
{%- endif -%}
{%- endif -%}
{%- unless flex_opens_with_banner -%}
{%- include "/sections/_breadcrumbs.liquid" -%}
{%- endunless -%}
{%- include "/sections/_flex.liquid" -%}
{%- include "/sections/_simple_cta.liquid" -%}
{%- include "/_footer.liquid" -%}
Loops flex_sections and includes the matching flexitem partial for each type.
{% comment %}
Allow editors to define multiple flexible sections to be displayed sequentially on the page.
Note that this approach makes the template incredibly flexible, but comes at the cost of making it
more complicated for editors and easier for them to "mess things up". As such it should be used sparingly.
Inputs:
flex_sp_imagepreset (passed through to the split_content section template)
Custom Fields:
flex_sections (name, type, <type specific settings>, color_scheme, padding_top, padding_bottom, section_class, hide_section).
Outputs:
section_rendered - true when this section outputs markup, false otherwise
{% endcomment -%}
{%- var headinglevel = headinglevel %}{% comment %}Copy to current scope{% endcomment -%}
{%- var minimumheadinglevel = headinglevel -%}{% if minimumheadinglevel == 1 %}{% set minimumheadinglevel = 2 %}{% endif -%}
{%- set section_rendered = false -%}
{%- for var section in entity.flex_sections -%}
{%- unless section.hide_section.on -%}
{%- var pad_top = section.padding_top.value -%}
{%- var pad_bottom = section.padding_bottom.value -%}
{%- if pad_top == 'pt-auto' or pad_top == '' %}{% set pad_top = 'pt-5' %}{% endif -%}
{%- if pad_bottom == 'pb-auto' or pad_bottom == '' %}{% set pad_bottom = 'pb-5' %}{% endif -%}
{%- capture var section_class -%}
{%- if section.color_scheme.is_valid %}{{ section.color_scheme.value}} {% endif -%}
{%- if pad_top is_valid %}{{ pad_top }} {% endif -%}
{%- if pad_bottom is_valid %}{{ pad_bottom }} {% endif -%}
{%- if section.section_class.is_valid %}{{ section.section_class.value}} {% endif -%}
{%- endcapture -%}
<section{% if section_class is_valid %} class="{{ section_class | strip | escape }}"{% endif %}>
{%- template var tpl = "/partials/flexitem/_" | append: section.type.value | append: ".liquid" -%}
{%- if tpl.is_valid -%}
{%- include tpl -%}
{%- endif -%}
</section>
{%- set section_rendered = true -%}
{%- endunless -%}
{%- endfor -%}
Repeating flex_sections fieldset owned by this section.
[
{
"Type": "fieldset",
"FieldID": "flex_sections",
"Label": "Flex Sections",
"Fields": [
{
"Type": "text",
"FieldID": "name",
"Label": "Name",
"Condition": null,
"IsRequired": true,
"Validators": []
},
{
"Type": "select",
"FieldID": "type",
"Label": "Type",
"IsRequired": true,
"AllowMultiple": false,
"Options": "title|Title;banner|Banner;cta|CTA;html|HTML;split_content|Split Content",
"Delimiter": ";",
"ValueDelimiter": "|"
},
{
"Type": "group",
"Label": "Title",
"Condition": {
"Type": "or",
"Conditions": [
{
"FieldID": "type",
"Type": "eq",
"Value": "title"
},
{
"FieldID": "type",
"Type": "eq",
"Value": "split_content"
},
{
"FieldID": "type",
"Type": "eq",
"Value": "html"
}
]
},
"Fields": [
{
"Type": "text",
"FieldID": "title",
"Label": "Title"
},
{
"Type": "text",
"FieldID": "subtitle",
"Label": "Subtitle/Description"
},
{
"Type": "group",
"Label": "Advanced",
"Collapsible": true,
"Collapsed": true,
"Fields": [
{
"Type": "text",
"FieldID": "title_classname",
"Label": "Title Classname",
"Placeholder": "h1 text-primary",
"Subtext": "The classname to use for the title. If you are unsure what to use, leave blank to use the default value."
},
{
"Type": "text",
"FieldID": "subtitle_classname",
"Label": "Subtitle Classname",
"Placeholder": "text-muted",
"Subtext": "The classname to use for the subtitle. If you are unsure what to use, leave blank to use the default value.",
"Condition": {
"FieldID": "subtitle",
"Type": "exists"
}
},
{
"Type": "radio",
"FieldID": "heading_treatment",
"Label": "Heading Level",
"Subtext": "Increment or decrement the heading level on each row to build the proper heading hierarchy for this page. The heading level will never go below the original heading level. Note that there can also only be one h1, which will automatically be handled by the system.",
"Options": "keep|Keep Current; increment|Increment; decrement|Decrement; decrement2|Decrement 2",
"Delimiter": ";",
"ValueDelimiter": "|",
"DefaultValue": "keep"
}
]
}
]
},
{
"Type": "group",
"Label": "Banner",
"Condition": {
"FieldID": "type",
"Type": "eq",
"Value": "banner"
},
"Fields": [
{
"Type": "text",
"FieldID": "banner_pretitle",
"Label": "Pre-Title",
"Placeholder": "Optional eyebrow text above the title"
},
{
"Type": "text",
"FieldID": "banner_title",
"Label": "Title",
"IsRequired": true
},
{
"Type": "text",
"FieldID": "banner_subtitle",
"Label": "Subtitle",
"Placeholder": "Optional supporting line under the banner title"
},
{
"Type": "radio",
"FieldID": "banner_heading_treatment",
"Label": "Heading Level",
"Subtext": "Increment or decrement the heading level on each row to build the proper heading hierarchy for this page. The heading level will never go below the original heading level. Note that there can also only be one h1, which will automatically be handled by the system.",
"Options": "keep|Keep Current; increment|Increment; decrement|Decrement; decrement2|Decrement 2",
"Delimiter": ";",
"ValueDelimiter": "|",
"DefaultValue": "keep"
},
{
"Type": "fieldset",
"FieldID": "banner_cta_buttons",
"Label": "CTA Buttons",
"AllowMultiple": true,
"InitCollapsed": false,
"Validators": [
{
"Type": "maxitems",
"Value": 2,
"Message": "You may not add more than 2 buttons"
}
],
"Fields": [
{
"Type": "text",
"FieldID": "button_text",
"Label": "Button Text",
"DefaultValue": "Learn More"
},
{
"Type": "url",
"FieldID": "button_url",
"Label": "Button URL"
}
]
},
{
"Type": "image",
"FieldID": "banner_image",
"Label": "Background Image"
},
{
"Type": "group",
"Label": "Banner Settings",
"Collapsible": true,
"Collapsed": true,
"Fields": [
{
"Type": "select",
"FieldID": "min_height",
"Label": "Minimum Height",
"Subtext": "Controls the minimum height of the banner.",
"Options": "230px|Compact; 460px|Medium; 600px|Hero",
"Delimiter": ";",
"ValueDelimiter": "|",
"DefaultValue": "460px"
},
{
"Type": "select",
"FieldID": "overlay_opacity",
"Label": "Overlay Darkness",
"Subtext": "Darkens the background image so text remains readable.",
"Options": "25|Light; 50|Medium; 75|Dark",
"Delimiter": ";",
"ValueDelimiter": "|",
"DefaultValue": "75"
},
{
"Type": "select",
"FieldID": "text_align",
"Label": "Text Alignment",
"Options": "start|Left; center|Center; end|Right",
"Delimiter": ";",
"ValueDelimiter": "|",
"DefaultValue": "start"
}
]
}
]
},
{
"Type": "snippet",
"FieldID": "cta",
"Label": "CTA",
"Condition": {
"FieldID": "type",
"Type": "eq",
"Value": "cta"
},
"IsRequired": true
},
{
"Type": "html",
"FieldID": "html",
"Label": "HTML Content",
"Condition": {
"FieldID": "type",
"Type": "eq",
"Value": "html"
},
"IsRequired": true
},
{
"Type": "group",
"Label": "Content",
"Condition": {
"FieldID": "type",
"Type": "eq",
"Value": "split_content"
},
"Collapsible": true,
"Fields": [
{
"Type": "group",
"Label": "Left Content",
"Fields": [
{
"Type": "radio",
"FieldID": "sc_left_type",
"Label": "Type",
"Options": "Image;HTML",
"Delimiter": ";",
"DefaultValue": "Image"
},
{
"Type": "image",
"FieldID": "sc_left_image",
"Label": "Image",
"IsRequired": true,
"Condition": {
"FieldID": "sc_left_type",
"Type": "eq",
"Value": "Image"
}
},
{
"Type": "html",
"FieldID": "sc_left_html",
"Label": "HTML",
"IsRequired": true,
"Condition": {
"FieldID": "sc_left_type",
"Type": "eq",
"Value": "HTML"
}
}
]
},
{
"Type": "group",
"Label": "Right Content",
"Fields": [
{
"Type": "radio",
"FieldID": "sc_right_type",
"Label": "Type",
"Options": "Image;HTML",
"Delimiter": ";",
"DefaultValue": "HTML"
},
{
"Type": "image",
"FieldID": "sc_right_image",
"Label": "Image",
"IsRequired": true,
"Condition": {
"FieldID": "sc_right_type",
"Type": "eq",
"Value": "Image"
}
},
{
"Type": "html",
"FieldID": "sc_right_html",
"Label": "HTML",
"IsRequired": true,
"Condition": {
"FieldID": "sc_right_type",
"Type": "eq",
"Value": "HTML"
}
}
]
}
]
},
{
"Type": "group",
"Label": "Layout",
"Condition": {
"FieldID": "type",
"Type": "eq",
"Value": "split_content"
},
"Collapsible": true,
"Collapsed": true,
"Fields": [
{
"Type": "radio",
"FieldID": "sc_left_width",
"Label": "Left Column Width",
"Options": "3:One Fourth; 4:One Third; 6:One Half; 8:Two Thirds; 9:Three Fourth",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": "6"
},
{
"Type": "select",
"FieldID": "sc_left_padding",
"Label": "Padding",
"Condition": null,
"IsRequired": false,
"Validators": [],
"Options": "p-auto:Auto; p-0:None; p-1:Small; p-2:Medium; p-3:Large; p-4:Extra Large; p-5:Max;",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": "p-auto"
},
{
"Type": "select",
"FieldID": "sc_right_padding",
"Label": "Padding",
"Condition": null,
"IsRequired": false,
"Validators": [],
"Options": "p-auto:Auto; p-0:None; p-1:Small; p-2:Medium; p-3:Large; p-4:Extra Large; p-5:Max;",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": "p-auto"
},
{
"Type": "checkbox",
"FieldID": "sc_reverse_on_mobile",
"Label": "Show Right Content First on Mobile"
}
]
},
{
"Type": "group",
"Label": "Section Settings",
"Condition": null,
"Collapsible": true,
"Collapsed": true,
"Fields": [
{
"Type": "select",
"FieldID": "color_scheme",
"Label": "Color Scheme",
"Condition": null,
"IsRequired": false,
"Validators": [],
"Options": ":None;text-bg-primary:Primary;text-bg-info:Info;text-bg-secondary:Secondary;text-bg-dark:Dark;text-bg-light:Light;",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": ""
},
{
"Type": "select",
"FieldID": "padding_top",
"Label": "Padding Top",
"Condition": null,
"IsRequired": false,
"Validators": [],
"Options": "pt-auto:Auto; pt-0:None; pt-1:Small; pt-2:Medium; pt-3:Large; pt-4:Extra Large; pt-5:Max;",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": "pt-auto"
},
{
"Type": "select",
"FieldID": "padding_bottom",
"Label": "Padding Bottom",
"Condition": null,
"IsRequired": false,
"Validators": [],
"Options": "pb-auto:Auto; pb-0:None; pb-1:Small; pb-2:Medium; pb-3:Large; pb-4:Extra Large; pb-5:Max;",
"Delimiter": ";",
"ValueDelimiter": ":",
"DefaultValue": "pb-auto"
},
{
"Type": "text",
"FieldID": "section_class",
"Label": "Section Class (advanced)",
"Subtext": "Add custom classes to the section. Use this for advanced styling or to override the default styles. If you are unsure what to use, leave blank."
},
{
"Type": "toggle",
"FieldID": "hide_section",
"Label": "Hide Section",
"Subtext": "Hide this section from the page. Useful while working on the page or for temporary changes.",
"OnLabel": "Hide",
"OnValue": "hide",
"OnColor": "red",
"OffLabel": "Show",
"OffValue": "show",
"OffColor": "green",
"DefaultValue": false
}
]
}
],
"AllowMultiple": true,
"InitCollapsed": false
}
]
Flex item type: banner block.
{% comment %}
Outputs a flex section with type = banner.
Hero-style banner with optional pre-title, intro text, and CTA buttons.
Inputs:
section
img_preset_banner_bg - image preset to use for the background image
{% endcomment -%}
{%- if section.banner_title.is_valid or section.banner_image.is_valid -%}
{%- id banner_id = prefix:"Flex_Banner_" -%}
{%- var min_height = section.min_height.value | default: "420px" -%}
{%- var overlay_opacity = section.overlay_opacity.value | default: "75" -%}
{%- var text_align = section.text_align.value | default: "start" -%}
<div id="{{banner_id}}" class="hero-section d-flex align-items-center position-relative w-100" style="min-height: {{min_height}}">
<div class="bg-dark position-absolute top-0 start-0 end-0 bottom-0 opacity-{{overlay_opacity}}"></div>
<div class="container position-relative py-5">
<div class="row{% if text_align == 'center' %} justify-content-center{% endif %}">
<div class="col-lg-9 col-xl-8 px-3 text-{{text_align}}">
{%- if section.banner_pretitle.is_valid -%}
<p class="text-white text-uppercase mb-3 fw-semibold" style="letter-spacing: 0.08em;">{{ section.banner_pretitle }}</p>
{%- endif -%}
{%- include '_title.liquid' no_container:true heading_treatment_override:section.banner_heading_treatment.value title_override:section.banner_title subtitle_override:section.banner_subtitle title_div:false default_title_classname:'text-white text-uppercase mb-3 lh-sm display-5 fw-bold' default_subtitle_classname:'text-white opacity-75 fs-5 mb-4 lh-base' -%}
{%- if section.banner_cta_buttons.is_valid -%}
<div class="d-grid gap-3 d-sm-flex{% if text_align == 'center' %} justify-content-center{% endif %}">
{%- for button in section.banner_cta_buttons -%}
<a href="{{button.button_url.value}}" class="btn btn-{% cycle 'flexbannerbtns':'light', 'outline-light' %} px-4 py-3 fw-semibold text-uppercase rounded-0 text-decoration-none">{{button.button_text}}</a>
{%- endfor -%}
</div>
{%- endif -%}
</div>
</div>
</div>
</div>
{%- if section.banner_image.is_valid -%}
{%- add_stylesheet inline -%}
#{{banner_id}} {
background-image: url("{% image_url = section.banner_image preset:'webp' preset:img_preset_banner_bg %}");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
{%- end_stylesheet -%}
{%- endif -%}
{%- endif -%}
Flex item type: call-to-action block.
{% comment %}
Outputs a flex section with type = cta
Inputs:
section
{% endcomment -%}
<div class="container">
{%- if section.cta.is_valid -%}
<div class="rounded-4 text-bg-light border-0 shadow-sm px-3 px-md-4 py-2">
{{ section.cta }}
</div>
{%- endif -%}
</div>
Flex item type: raw HTML block.
{% comment %}
Outputs a flex section with type = html
Inputs:
section
{% endcomment -%}
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-10 col-xl-8">
{%- include '_title.liquid' no_container:true default_title_classname:'text-primary text-center' default_subtitle_classname:'text-muted text-center mb-4' -%}
{%- if section.html.is_valid -%}
<div class="flex-html-body fs-6 lh-lg">
{{ section.html }}
</div>
{%- endif -%}
</div>
</div>
</div>
Flex item type: split content row.
{% comment %}
Outputs a flex section with type = split_content
Inputs:
section
flex_sp_imagepreset - An optional image preset to use for the split content images
{% endcomment -%}
<div class="container">
{%- include "_title.liquid" no_container:true default_title_classname:'text-primary text-center' default_subtitle_classname:'text-muted text-center mb-4' -%}
<div class="row g-4 g-lg-5 align-items-center">
{%- var sc_left_width = section.sc_left_width.value | default: 6 | to_int | at_least: 1 | at_most: 11 -%}
{%- var sc_right_width = 12 | minus: sc_left_width -%}
{%- unless section.sc_reverse_on_mobile.checked -%}
{%- include '_split_content_column.liquid' colname:'left' -%}
{%- include '_split_content_column.liquid' colname:'right' -%}
{%- else -%}
{%- include '_split_content_column.liquid' colname:'right' sc_col_classname:'order-1 order-md-2' -%}
{%- include '_split_content_column.liquid' colname:'left' sc_col_classname:'order-2 order-md-1' -%}
{%- endunless -%}
</div>
</div>
Column inside a split-content flex item.
{% comment %}
Outputs either the left or the right column of a flex section with type = split_content
Inputs:
section
colname - 'left' or 'right'
img_preset_flex_split - The image preset to use for the split content image
sc_col_classname - An optional classname to add to the column
Expects certain variables to exist on the scope and the section
sp_[colname]_width - a number between 1 and 11 - required
section.sp_[colname]_padding - optional
section.sp_[colname]_type - required
section.sp_[colname]_image - optional
section.sp_[colname]_html - optional
{% endcomment -%}
{%- var colprefix = colname | prepend: 'sc_' -%}
{%- var widthvar = colprefix | append:'_width' -%}
{%- var paddingvar = colprefix | append:'_padding' -%}
{%- var typevar = colprefix | append:'_type' -%}
{%- capture var colcontent -%}
{%- if section[typevar].value == "Image" -%}
{%- var imagevar = colprefix | append:'_image' -%}
{%- img section[imagevar] link:false preset:img_preset_flex_split class:'img-fluid rounded-3 w-100' -%}
{%- elsif section[typevar].value == "HTML" -%}
{%- var htmlvar = colprefix | append:'_html' -%}
{{ section[htmlvar] }}
{%- endif -%}
{%- endcapture -%}
{%- if colcontent is_valid %}
<div class="col col-sm-12 col-md-{{ [widthvar] }}{% if section[paddingvar].is_valid %} {{section[paddingvar].value}}{% endif %}{% if sc_col_classname is_valid %} {{sc_col_classname}}{% endif %}">
{{colcontent}}
</div>
{%- endif -%}Flex item type: title block.
{% comment %}
Outputs a flex section with type = title
Inputs:
section
no_container - set to true to prevent this template from wrapping its output in <div class="container">
minimumheadinglevel - initialized in /sections/_flex.liquid to the original headinglevel of the whole flex section (or 2, if the original headinglevel was 1)
default_title_classname
default_subtitle_classname
title_override - if set, this will be used instead of section.title
subtitle_override - if set, this will be used instead of section.subtitle
heading_treatment_override - if set, this will be used instead of section.heading_treatment
title_div - true/false
title_div_classname
title_link
Outputs:
headinglevel - may be updated on the parent scope based on the section.heading_treatment, minimumheadinglevel, and do_not_change_headinglevel variables.
Note: incrementing and deprecating heading levels should happen BEFORE outputting the title
{% endcomment -%}
{%- var title = title_override | default:section.title -%}
{%- var subtitle = subtitle_override | default:section.subtitle -%}
{%- var title_classname = section.title_classname | default:default_title_classname -%}
{%- var subtitle_classname = section.subtitle_classname | default:default_subtitle_classname -%}
{%- if title is_valid -%}
{%- var heading_treatment = heading_treatment_override | default: section.heading_treatment.value %}{% if headinglevel == 1 or do_not_change_headinglevel %}{% set heading_treatment = 'keep' %}{% endif %}
{%- if heading_treatment == 'increment' -%}
{%- set headinglevel = headinglevel | plus: 1 -%}
{%- elsif heading_treatment == 'decrement' and headinglevel > minimumheadinglevel -%}
{%- set headinglevel = headinglevel | minus: 1 -%}
{%- elsif heading_treatment == 'decrement2' -%}
{%- set headinglevel = headinglevel | minus: 2 | at_most: minimumheadinglevel -%}
{%- endif -%}
{%- endif -%}
{%- if title is_valid or subtitle is_valid -%}
{%- unless no_container %}<div class="container">{% endunless -%}
{%- include "/common/_title_with_subtitle.liquid" -%}
{%- unless no_container %}</div>{% endunless -%}
{%- endif -%}