Global UI: Footer Beginner 8 min read

Social Links and Policy Links

Add social media icons, payment methods, policy links, and copyright notices to your footer using Shopify's built-in settings and objects.

Every footer needs certain standard elements: social links, policy links, payment icons, and copyright. Shopify provides built-in objects and settings to make these easy to implement.

Using Theme Settings

Configure social links in theme settings (not section settings) so they’re consistent across the site:

{# config/settings_schema.json #}
{
"name": "Social media",
"settings": [
{
"type": "header",
"content": "Accounts"
},
{
"type": "text",
"id": "social_facebook",
"label": "Facebook",
"info": "https://facebook.com/shopify"
},
{
"type": "text",
"id": "social_instagram",
"label": "Instagram",
"info": "https://instagram.com/shopify"
},
{
"type": "text",
"id": "social_twitter",
"label": "X (Twitter)",
"info": "https://twitter.com/shopify"
},
{
"type": "text",
"id": "social_youtube",
"label": "YouTube",
"info": "https://youtube.com/shopify"
},
{
"type": "text",
"id": "social_tiktok",
"label": "TikTok",
"info": "https://tiktok.com/@shopify"
},
{
"type": "text",
"id": "social_pinterest",
"label": "Pinterest",
"info": "https://pinterest.com/shopify"
},
{
"type": "text",
"id": "social_linkedin",
"label": "LinkedIn",
"info": "https://linkedin.com/company/shopify"
}
]
}
{# snippets/social-icons.liquid #}
{%- liquid
assign social_accounts = 'facebook, instagram, twitter, youtube, tiktok, pinterest, linkedin, snapchat, tumblr, vimeo' | split: ', '
assign has_social = false
for account in social_accounts
assign setting_name = 'social_' | append: account
if settings[setting_name] != blank
assign has_social = true
break
endif
endfor
-%}
{%- if has_social -%}
<ul class="social-icons" role="list">
{%- for account in social_accounts -%}
{%- assign setting_name = 'social_' | append: account -%}
{%- assign url = settings[setting_name] -%}
{%- if url != blank -%}
<li class="social-icons__item">
<a
href="{{ url }}"
class="social-icons__link"
target="_blank"
rel="noopener noreferrer"
aria-label="{{ account | capitalize }}"
>
{%- render 'icon-social', icon: account -%}
</a>
</li>
{%- endif -%}
{%- endfor -%}
</ul>
{%- endif -%}

Social Icon Snippet

{# snippets/icon-social.liquid #}
{%- case icon -%}
{%- when 'facebook' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"/>
</svg>
{%- when 'instagram' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"/>
<path d="M16 11.37A4 4 0 1112.63 8 4 4 0 0116 11.37z"/>
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/>
</svg>
{%- when 'twitter' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
{%- when 'youtube' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M23.498 6.186a3.016 3.016 0 00-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 00.502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 002.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 002.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>
</svg>
{%- when 'tiktok' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M19.59 6.69a4.83 4.83 0 01-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 01-5.2 1.74 2.89 2.89 0 012.31-4.64 2.93 2.93 0 01.88.13V9.4a6.84 6.84 0 00-1-.05A6.33 6.33 0 005 20.1a6.34 6.34 0 0010.86-4.43v-7a8.16 8.16 0 004.77 1.52v-3.4a4.85 4.85 0 01-1-.1z"/>
</svg>
{%- when 'pinterest' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 01.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/>
</svg>
{%- when 'linkedin' -%}
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
{%- endcase -%}

Social Icons CSS

.social-icons {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-sm);
list-style: none;
padding: 0;
margin: 0;
}
.social-icons__link {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: inherit;
opacity: 0.7;
transition: opacity 0.2s;
}
.social-icons__link:hover {
opacity: 1;
}
.social-icons__link svg {
width: 20px;
height: 20px;
}

Shopify provides a shop.policies object with all store policies:

{# snippets/policy-links.liquid #}
{%- if shop.policies.size > 0 -%}
<nav class="policy-links" aria-label="Legal">
<ul class="policy-links__list">
{%- for policy in shop.policies -%}
{%- if policy != blank -%}
<li class="policy-links__item">
<a href="{{ policy.url }}" class="policy-links__link">
{{ policy.title }}
</a>
</li>
{%- endif -%}
{%- endfor -%}
</ul>
</nav>
{%- endif -%}

Available Policies

The shop.policies array can include:

  • shop.policies.refund_policy
  • shop.policies.privacy_policy
  • shop.policies.terms_of_service
  • shop.policies.shipping_policy
  • shop.policies.subscription_policy

Access individual policies directly:

{%- if shop.privacy_policy -%}
<a href="{{ shop.privacy_policy.url }}">{{ shop.privacy_policy.title }}</a>
{%- endif -%}
.policy-links__list {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-sm) var(--spacing-md);
list-style: none;
padding: 0;
margin: 0;
}
.policy-links__link {
font-size: 0.875rem;
color: rgba(255, 255, 255, 0.6);
text-decoration: none;
transition: color 0.2s;
}
.policy-links__link:hover {
color: #ffffff;
}

Payment Icons

Display accepted payment methods using Shopify’s payment icons:

{# snippets/payment-icons.liquid #}
{%- unless shop.enabled_payment_types == empty -%}
<div class="payment-icons">
<span class="visually-hidden">Payment methods</span>
<ul class="payment-icons__list" role="list">
{%- for type in shop.enabled_payment_types -%}
<li class="payment-icons__item">
{{ type | payment_type_svg_tag: class: 'payment-icon' }}
</li>
{%- endfor -%}
</ul>
</div>
{%- endunless -%}

Payment Icons CSS

.payment-icons__list {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-xs);
list-style: none;
padding: 0;
margin: 0;
}
.payment-icon {
height: 24px;
width: auto;
}
/* Or fixed width for alignment */
.payment-icons__item {
width: 38px;
height: 24px;
}
.payment-icon {
width: 100%;
height: 100%;
object-fit: contain;
}

Dynamic copyright with current year:

{# Basic copyright #}
<p class="footer__copyright">
&copy; {{ 'now' | date: '%Y' }} {{ shop.name }}
</p>
{# With "All rights reserved" #}
<p class="footer__copyright">
&copy; {{ 'now' | date: '%Y' }} {{ shop.name }}. All rights reserved.
</p>
{# With customizable text from settings #}
<p class="footer__copyright">
&copy; {{ 'now' | date: '%Y' }} {{ shop.name }}.
{%- if section.settings.copyright_text != blank -%}
{{ section.settings.copyright_text }}
{%- endif -%}
</p>

Country/Currency Selector

For international stores:

{# snippets/country-selector.liquid #}
{%- if localization.available_countries.size > 1 -%}
<div class="country-selector">
{%- form 'localization', class: 'country-selector__form' -%}
<label for="country-selector" class="visually-hidden">
Country/region
</label>
<select
name="country_code"
id="country-selector"
class="country-selector__select"
onchange="this.form.submit()"
>
{%- for country in localization.available_countries -%}
<option
value="{{ country.iso_code }}"
{% if country.iso_code == localization.country.iso_code %}selected{% endif %}
>
{{ country.name }} ({{ country.currency.iso_code }} {{ country.currency.symbol }})
</option>
{%- endfor -%}
</select>
<button type="submit" class="country-selector__button visually-hidden">
Update
</button>
{%- endform -%}
</div>
{%- endif -%}

Language Selector

{# snippets/language-selector.liquid #}
{%- if localization.available_languages.size > 1 -%}
<div class="language-selector">
{%- form 'localization', class: 'language-selector__form' -%}
<label for="language-selector" class="visually-hidden">
Language
</label>
<select
name="locale_code"
id="language-selector"
class="language-selector__select"
onchange="this.form.submit()"
>
{%- for language in localization.available_languages -%}
<option
value="{{ language.iso_code }}"
{% if language.iso_code == localization.language.iso_code %}selected{% endif %}
>
{{ language.endonym_name | capitalize }}
</option>
{%- endfor -%}
</select>
<button type="submit" class="visually-hidden">
Update
</button>
{%- endform -%}
</div>
{%- endif -%}

Putting it all together:

<div class="footer__bottom">
<div class="footer__bottom-container container">
<div class="footer__bottom-left">
{# Copyright #}
<p class="footer__copyright">
&copy; {{ 'now' | date: '%Y' }} {{ shop.name }}
</p>
{# Policy links #}
{%- render 'policy-links' -%}
</div>
<div class="footer__bottom-center">
{# Social icons #}
{%- render 'social-icons' -%}
</div>
<div class="footer__bottom-right">
{# Selectors #}
<div class="footer__selectors">
{%- render 'country-selector' -%}
{%- render 'language-selector' -%}
</div>
{# Payment icons #}
{%- render 'payment-icons' -%}
</div>
</div>
</div>
.footer__bottom {
padding-top: var(--spacing-lg);
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.footer__bottom-container {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--spacing-md);
}
.footer__bottom-left {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--spacing-md);
}
.footer__bottom-right {
display: flex;
align-items: center;
gap: var(--spacing-lg);
}
.footer__selectors {
display: flex;
gap: var(--spacing-sm);
}
/* Mobile: Stack vertically */
@media (max-width: 767px) {
.footer__bottom-container {
flex-direction: column;
text-align: center;
}
.footer__bottom-left,
.footer__bottom-right {
justify-content: center;
}
}

Practice Exercise

Create a footer bottom bar that includes:

  1. Copyright with dynamic year
  2. Social links from theme settings
  3. Policy links from shop.policies
  4. Payment icons
  5. Country selector (if multiple countries)

Test by:

  • Adding/removing social URLs in theme settings
  • Checking that all policies display
  • Verifying payment icons match your store’s settings

Key Takeaways

  1. Use theme settings for social links (consistent across site)
  2. shop.policies provides all store policies automatically
  3. payment_type_svg_tag renders payment method icons
  4. Dynamic year with {{ 'now' | date: '%Y' }}
  5. Localization forms for country/language selectors
  6. Use aria-label on social links for accessibility
  7. target="_blank" with rel="noopener" for external links

What’s Next?

With all footer elements in place, the next lesson covers Accessibility for Navigation Regions to ensure your header and footer work for everyone.

Finished this lesson?

Mark it complete to track your progress.

Discussion

Loading comments...