In this tutorial, we’ll show you how to set up a visual custom drawer menu to help your customers find your products quickly and easily.
Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).
Create new metafield
For any object (ex: product, collection, page, etc) that you want to assign a menu image, create a new metafield with the following properties:
- Name: Header Menu Image
- Namespace and key: custom.header_menu_image
- Type: File
Edit settings_schema.json
{
"name": "Custom Header Drawer Menu",
"settings": [
{
"type": "checkbox",
"id": "enable_custom_drawer_menu",
"label": "Enable Custom Drawer Menu",
"info": "If enabled, the custom drawer menu will be used instead of the standard drawer menu.",
"default": false
},
{
"type": "link_list",
"id": "drawer_menu",
"label": "Drawer Menu",
"info": "This menu will be used for the drawer menu. Defaults to header menu if left blank."
},
{
"type": "select",
"id": "drawer_menu_images_toggle",
"options": [
{
"value": "featured",
"label": "Featured"
},
{
"value": "metafield",
"label": "Metafield"
}
],
"default": "featured",
"label": "Drawer menu collection image type"
},
{
"type": "header",
"content": "Menu Title Styling"
},
{
"type": "range",
"id": "drawer_menu_title_size",
"min": 1.0,
"max": 3.0,
"step": 0.1,
"unit": "rem",
"label": "Title Font Size",
"default": 1.8
},
{
"type": "color",
"id": "drawer_menu_title_bg",
"label": "Title Background Color",
"default": "#f4f4f4"
},
{
"type": "color",
"id": "drawer_menu_title_color",
"label": "Title Text Color",
"default": "#333333"
}
]
}
Edit header.liquid
if section.settings.menu != blank or settings.drawer_menu != blank
if settings.enable_custom_drawer_menu
if settings.drawer_menu != blank
assign custom_drawer_menu = settings.drawer_menu
else
assign custom_drawer_menu = section.settings.menu
endif
render 'header-drawer-custom', menu: custom_drawer_menu
else
if section.settings.menu != blank
render 'header-drawer'
endif
endif
endif
Create new snippet file header-drawer-custom.liquid
{% comment %}
Renders a header drawer menu with grid layout for mobile and desktop.
Usage:
{% render 'header-drawer-2' %}
{% endcomment %}
<header-drawer data-breakpoint="{% if section.settings.menu_type_desktop == 'drawer' %}desktop{% else %}tablet{% endif %}">
<details id="Details-menu-drawer-container" class="menu-drawer-container">
<summary
class="header__icon header__icon--menu header__icon--summary link focus-inset"
aria-label="{{ 'sections.header.menu' | t }}"
>
<span>
{{- 'icon-hamburger.svg' | inline_asset_content -}}
{{- 'icon-close.svg' | inline_asset_content -}}
</span>
</summary>
<div id="menu-drawer" class="gradient menu-drawer motion-reduce color-{{ section.settings.menu_color_scheme }}">
<div class="menu-drawer__inner-container">
<div class="menu-drawer__navigation-container">
<nav class="menu-drawer__navigation">
<div class="drawer-menu-grid">
{%- for link in menu.links -%}
{% assign has_image = false %}
{% if settings.drawer_menu_images_toggle == 'featured' and link.object.featured_image %}
{% assign has_image = true %}
{% assign menu_image_url = link.object.featured_image | image_url: width: menu_images_size, height: menu_images_size %}
{% elsif settings.drawer_menu_images_toggle == 'metafield' and link.object.metafields.custom.header_menu_image %}
{% assign has_image = true %}
{% assign menu_image_url = link.object.metafields.custom.header_menu_image | image_url: width: menu_images_size, height: menu_images_size %}
{% endif %}
{% if has_image %}
<div class="drawer-menu-grid-item">
<a href="{{ link.url }}" class="drawer-menu-grid-link">
<div class="drawer-menu-grid-image-wrapper">
{{ menu_image_url | image_url: width: 300 | image_tag }}
</div>
<div class="drawer-menu-grid-title-wrapper">
<span class="drawer-menu-grid-title">{{ link.title | escape }}</span>
</div>
</a>
</div>
{% endif %}
{%- endfor -%}
</div>
<ul class="menu-drawer__menu has-submenu list-menu drawer-menu-list" role="list">
{%- for link in menu.links -%}
{% assign has_image = false %}
{% if settings.drawer_menu_images_toggle == 'featured' and link.object.featured_image %}
{% assign has_image = true %}
{% elsif settings.drawer_menu_images_toggle == 'metafield' and link.object.metafields.custom.header_menu_image %}
{% assign has_image = true %}
{% endif %}
{% unless has_image %}
<li>
{%- if link.links != blank -%}
<details id="Details-menu-drawer-menu-item-{{ forloop.index }}">
<summary
id="HeaderDrawer-{{ link.handle }}"
class="menu-drawer__menu-item list-menu__item link link--text focus-inset{% if link.child_active %} menu-drawer__menu-item--active{% endif %}"
>
{{ link.title | escape }}
<span class="svg-wrapper">
{{- 'icon-arrow.svg' | inline_asset_content -}}
</span>
<span class="svg-wrapper">
{{- 'icon-caret.svg' | inline_asset_content -}}
</span>
</summary>
<div
id="link-{{ link.handle | escape }}"
class="menu-drawer__submenu has-submenu gradient motion-reduce"
tabindex="-1"
>
<div class="menu-drawer__inner-submenu">
<button class="menu-drawer__close-button link link--text focus-inset" aria-expanded="true">
<span class="svg-wrapper">
{{- 'icon-arrow.svg' | inline_asset_content -}}
</span>
{{ link.title | escape }}
</button>
<ul class="menu-drawer__menu list-menu" role="list" tabindex="-1">
{%- for childlink in link.links -%}
<li>
<a
id="HeaderDrawer-{{ link.handle }}-{{ childlink.handle }}"
href="{{ childlink.url }}"
class="menu-drawer__menu-item link link--text list-menu__item focus-inset{% if childlink.current %} menu-drawer__menu-item--active{% endif %}"
{% if childlink.current %}aria-current="page"{% endif %}
>
{{ childlink.title | escape }}
</a>
</li>
{%- endfor -%}
</ul>
</div>
</div>
</details>
{%- else -%}
<a
id="HeaderDrawer-{{ link.handle }}"
href="{{ link.url }}"
class="menu-drawer__menu-item list-menu__item link link--text focus-inset{% if link.current %} menu-drawer__menu-item--active{% endif %}"
{% if link.current %}aria-current="page"{% endif %}
>
{{ link.title | escape }}
</a>
{%- endif -%}
</li>
{% endunless %}
{%- endfor -%}
</ul>
</nav>
<div class="menu-drawer__utility-links">
{%- if shop.customer_accounts_enabled -%}
<a
href="{%- if customer -%}{{ routes.account_url }}{%- else -%}{{ routes.account_login_url }}{%- endif -%}"
class="menu-drawer__account link focus-inset h5 medium-hide large-up-hide"
>
{%- if section.settings.enable_customer_avatar -%}
<account-icon>
{%- if customer and customer.has_avatar? -%}
{{ customer | avatar }}
{%- else -%}
<span class="svg-wrapper">
{{- 'icon-account.svg' | inline_asset_content -}}
</span>
{%- endif -%}
</account-icon>
{%- else -%}
<span class="svg-wrapper">
{{- 'icon-account.svg' | inline_asset_content -}}
</span>
{%- endif -%}
{%- liquid
if customer
echo 'customer.account_fallback' | t
else
echo 'customer.log_in' | t
endif
-%}
</a>
{%- endif -%}
{%- if localization.available_countries or localization.available_languages -%}
<div class="menu-drawer__localization header-localization">
{%- if localization.available_countries and localization.available_countries.size > 1 -%}
<localization-form>
{%- form 'localization', id: 'HeaderCountryMobileForm', class: 'localization-form' -%}
<div>
<h2 class="visually-hidden" id="HeaderCountryMobileLabel">
{{ 'localization.country_label' | t }}
</h2>
{%- render 'country-localization', localPosition: 'HeaderCountryMobile' -%}
</div>
{%- endform -%}
</localization-form>
{% endif %}
{%- if localization.available_languages and localization.available_languages.size > 1 -%}
<localization-form>
{%- form 'localization', id: 'HeaderLanguageMobileForm', class: 'localization-form' -%}
<div>
<h2 class="visually-hidden" id="HeaderLanguageMobileLabel">
{{ 'localization.language_label' | t }}
</h2>
{%- render 'language-localization', localPosition: 'HeaderLanguageMobile' -%}
</div>
{%- endform -%}
</localization-form>
{%- endif -%}
</div>
{%- endif -%}
<ul class="list list-social list-unstyled" role="list">
{%- if settings.social_twitter_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_twitter_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-twitter.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.twitter' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_facebook_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_facebook_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-facebook.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.facebook' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_pinterest_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_pinterest_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-pinterest.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.pinterest' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_instagram_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_instagram_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-instagram.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.instagram' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_tiktok_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_tiktok_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-tiktok.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.tiktok' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_tumblr_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_tumblr_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-tumblr.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.tumblr' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_snapchat_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_snapchat_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-snapchat.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.snapchat' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_youtube_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_youtube_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-youtube.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.youtube' | t }}</span>
</a>
</li>
{%- endif -%}
{%- if settings.social_vimeo_link != blank -%}
<li class="list-social__item">
<a href="{{ settings.social_vimeo_link }}" class="list-social__link link">
<span class="svg-wrapper">
{{- 'icon-vimeo.svg' | inline_asset_content -}}
</span>
<span class="visually-hidden">{{ 'general.social.links.vimeo' | t }}</span>
</a>
</li>
{%- endif -%}
</ul>
</div>
</div>
</div>
</div>
</details>
</header-drawer>
<style>
.drawer-menu-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2rem;
padding: 2rem;
}
.drawer-menu-grid-item {
text-align: center;
border-radius: 24px;
overflow: hidden;
background: white;
aspect-ratio: 1;
}
.drawer-menu-grid-link {
display: flex;
flex-direction: column;
text-decoration: none;
color: inherit;
height: 100%;
}
.drawer-menu-grid-image-wrapper {
height: 80%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: white;
overflow: hidden;
}
.drawer-menu-grid-image-wrapper img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.drawer-menu-grid-title-wrapper {
height: 20%;
background: {{ settings.drawer_menu_title_bg }};
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
}
.drawer-menu-grid-title {
font-size: {{ settings.drawer_menu_title_size }}rem;
line-height: 1.2;
font-weight: 500;
color: {{ settings.drawer_menu_title_color }};
margin: 0;
}
.drawer-menu-list {
padding: 1rem;
border-top: 1px solid rgba(var(--color-foreground), 0.08);
margin-top: 1rem;
}
</style>