Theme Settings and Extensibility Intermediate 10 min read

App Blocks and Theme Compatibility

Learn how to make your theme compatible with Shopify app blocks, allowing merchants to add third-party functionality without code changes.

App blocks let Shopify apps inject content into themes without requiring code edits. Making your theme app-block compatible is essential for merchant flexibility and app ecosystem support.

What Are App Blocks?

App blocks are special section blocks that apps define. When a merchant installs an app, its blocks become available in the theme editor alongside your theme’s native blocks.

Benefits

  • No code changes required by merchants
  • Visual positioning in theme editor
  • Easy removal if app is uninstalled
  • Consistent experience across themes

Making Sections App-Block Compatible

Add the @app Block Type

Any section that should accept app blocks needs the @app block type:

{% schema %}
{
"name": "Product Information",
"blocks": [
{
"type": "title",
"name": "Title",
"limit": 1
},
{
"type": "price",
"name": "Price",
"limit": 1
},
{
"type": "description",
"name": "Description"
},
{
"type": "@app"
}
]
}
{% endschema %}

The @app type tells Shopify this section can host app blocks.

Rendering App Blocks

App blocks render like any other block:

{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'title' -%}
<h1 {{ block.shopify_attributes }}>{{ product.title }}</h1>
{%- when 'price' -%}
<div {{ block.shopify_attributes }}>
{{ product.price | money }}
</div>
{%- when 'description' -%}
<div {{ block.shopify_attributes }}>
{{ product.description }}
</div>
{%- when '@app' -%}
{# App blocks render themselves #}
{% render block %}
{%- endcase -%}
{%- endfor -%}

The {% render block %} tag outputs the app’s content.

Common App Block Locations

Product Page

{# sections/main-product.liquid #}
<div class="product">
<div class="product__media">
{# Media gallery #}
</div>
<div class="product__info">
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'title' -%}
<h1 {{ block.shopify_attributes }}>{{ product.title }}</h1>
{%- when 'price' -%}
{% render 'price', product: product, block: block %}
{%- when 'variant_picker' -%}
{% render 'variant-picker', product: product, block: block %}
{%- when 'buy_buttons' -%}
{% render 'buy-buttons', product: product, block: block %}
{%- when '@app' -%}
<div class="product__app-block" {{ block.shopify_attributes }}>
{% render block %}
</div>
{%- endcase -%}
{%- endfor -%}
</div>
</div>
{% schema %}
{
"name": "Product Information",
"blocks": [
{ "type": "title", "name": "Title", "limit": 1 },
{ "type": "price", "name": "Price", "limit": 1 },
{ "type": "variant_picker", "name": "Variant picker", "limit": 1 },
{ "type": "buy_buttons", "name": "Buy buttons", "limit": 1 },
{ "type": "description", "name": "Description" },
{ "type": "share", "name": "Share" },
{ "type": "@app" }
]
}
{% endschema %}

Cart Page

{# sections/main-cart.liquid #}
<div class="cart">
<div class="cart__items">
{# Cart items #}
</div>
<div class="cart__footer">
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'subtotal' -%}
<div {{ block.shopify_attributes }}>
<span>Subtotal</span>
<span>{{ cart.total_price | money }}</span>
</div>
{%- when 'checkout_button' -%}
<button type="submit" name="checkout" {{ block.shopify_attributes }}>
Checkout
</button>
{%- when '@app' -%}
<div class="cart__app-block" {{ block.shopify_attributes }}>
{% render block %}
</div>
{%- endcase -%}
{%- endfor -%}
</div>
</div>
{% schema %}
{
"name": "Cart",
"blocks": [
{ "type": "subtotal", "name": "Subtotal", "limit": 1 },
{ "type": "checkout_button", "name": "Checkout button", "limit": 1 },
{ "type": "@app" }
]
}
{% endschema %}

App Embed Blocks

Some apps use embed blocks instead of section blocks. These appear in the theme editor under Theme settings → App embeds.

Embed blocks don’t require section changes. They inject content globally (like chat widgets, announcement bars, or analytics).

Difference from App Blocks

App BlocksApp Embeds
Placed within sectionsGlobal theme additions
Position controlled by merchantUsually fixed position
Require @app block typeNo theme code needed
e.g., Reviews, wishlistse.g., Chat, notifications

Styling App Blocks

App blocks may not inherit your theme’s styles. Use defensive CSS:

/* Reset styles for app blocks */
.product__app-block {
margin: var(--spacing-md) 0;
}
/* Let apps control their own content */
.product__app-block > * {
/* Avoid overriding app styles */
}
/* But provide consistent container */
.cart__app-block {
padding: var(--spacing-sm) 0;
border-top: 1px solid var(--color-border);
}

Testing App Compatibility

Without Installing Apps

Use placeholder blocks to simulate app blocks:

{%- when '@app' -%}
<div class="app-block-placeholder" {{ block.shopify_attributes }}>
{% render block %}
</div>

In development, you can create test blocks:

{
"blocks": {
"app_1": {
"type": "@app"
}
}
}

With Test Apps

  1. Install a free app that uses app blocks (e.g., Shopify Reviews)
  2. Add its blocks to your sections
  3. Verify styling and positioning
  4. Test removal and reinstallation

Theme App Extensions

App developers create Theme App Extensions that define:

  • App blocks for sections
  • App embed blocks
  • App block settings

As a theme developer, you enable these by:

  1. Including @app in relevant sections
  2. Providing good default styling
  3. Testing with popular apps

Multiple @app Support

You can have multiple app blocks in a section:

{
"blocks": [
{ "type": "title", "name": "Title" },
{ "type": "@app" }
],
"presets": [
{
"name": "Product",
"blocks": [
{ "type": "title" }
]
}
]
}

Merchants can add as many app blocks as needed.

App Block Positioning

Control where app blocks appear relative to other content:

{# Before product info #}
{%- for block in section.blocks -%}
{%- if block.type == '@app' and block.settings.position == 'before' -%}
{% render block %}
{%- endif -%}
{%- endfor -%}
{# Product info #}
<div class="product__main">
{%- for block in section.blocks -%}
{%- unless block.type == '@app' -%}
{# Render theme blocks #}
{%- endunless -%}
{%- endfor -%}
</div>
{# After product info #}
{%- for block in section.blocks -%}
{%- if block.type == '@app' and block.settings.position != 'before' -%}
{% render block %}
{%- endif -%}
{%- endfor -%}

Or use settings:

{
"type": "@app"
}

Apps can define their own positioning preferences.

Add @app support to these sections:

SectionCommon App Blocks
Product pageReviews, wishlist, size guide
Collection pageFilters, quick view
CartUpsells, shipping calculator
FooterNewsletter apps, trust badges
Product cardQuick add, wishlist button

App Block Wrapper

Provide consistent containers:

{%- when '@app' -%}
<div
class="app-block app-block--{{ forloop.index }}"
{{ block.shopify_attributes }}
>
{% render block %}
</div>
.app-block {
/* Consistent spacing */
margin-block: var(--spacing-md);
}
.app-block:empty {
/* Hide if app renders nothing */
display: none;
}

Handling Missing Apps

When an app is uninstalled, its blocks remain in the JSON but render nothing:

{%- when '@app' -%}
{# This safely renders nothing if app is gone #}
{% render block %}

No error handling needed; Shopify handles this gracefully.

Best Practices

Do

  • Add @app to all major sections
  • Provide wrapper elements with styling
  • Test with popular apps
  • Document app block locations

Don’t

  • Override app styles aggressively
  • Assume app content dimensions
  • Require app blocks (make them optional)
  • Break layout if app block is empty

Practice Exercise

Add app block support to:

  1. Product information section
  2. Cart section
  3. Footer section

Test by:

  • Installing a reviews app
  • Adding app blocks in theme editor
  • Verifying layout doesn’t break
  • Removing app and checking graceful fallback

Key Takeaways

  1. @app block type enables app blocks
  2. {% render block %} outputs app content
  3. App embeds are global, no code needed
  4. Defensive styling prevents layout breaks
  5. Popular sections should support apps
  6. Graceful fallback when apps removed
  7. No special handling for missing apps

What’s Next?

The final lesson covers Upgrade-Safe Customization Patterns for maintainable theme modifications.

Finished this lesson?

Mark it complete to track your progress.

Discussion

Loading comments...