theme-extension — theme-extension install theme-extension, Avada-Simple-Sales-Pop, community, theme-extension install, ide skills, shopify liquid rendering, optimal storefront performance, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Ideal for E-commerce Development Agents requiring server-side rendering for high-performance Shopify storefronts. theme-extension is a development approach that uses Shopify's native Liquid rendering for server-rendered content, ensuring optimal storefront performance.

Features

Utilizes Shopify's native Liquid rendering for optimal storefront performance
Supports server-rendered content for static/semi-static and SEO-critical product displays
Follows a specific directory structure for theme extension development
Allows for static and semi-static content rendering
Enables SEO-critical content rendering for product displays
Uses a theme extension approach for optimal performance

# Core Topics

ducnm-mimhus ducnm-mimhus
[0]
[0]
Updated: 3/8/2026

Agent Capability Analysis

The theme-extension skill by ducnm-mimhus is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for theme-extension install, shopify liquid rendering, optimal storefront performance.

Ideal Agent Persona

Ideal for E-commerce Development Agents requiring server-side rendering for high-performance Shopify storefronts.

Core Value

Enables agents to leverage Shopify's native Liquid rendering for server-side content delivery, providing optimal storefront performance and SEO-critical product displays without client-side processing overhead.

Capabilities Granted for theme-extension

Rendering static/semi-static content blocks
Implementing SEO-optimized product displays
Developing server-rendered theme components

! Prerequisites & Limits

  • Not suitable for highly interactive widgets requiring real-time updates
  • Limited to Shopify's Liquid templating system
  • Requires Theme App Extension deployment structure
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

theme-extension

Install theme-extension, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Theme App Extension Development

Overview

Theme App Extensions use Shopify's native Liquid rendering for optimal storefront performance. Content is server-rendered before reaching the customer's browser.

When to Use

ApproachUse For
Theme ExtensionStatic/semi-static content, SEO-critical content, product displays
ScripttagHighly interactive widgets, real-time updates, complex UI

Directory Structure

extensions/theme-extension/
├── blocks/                    # App blocks (merchant can position)
│   ├── feature-block.liquid   # Main feature block
│   └── badge.liquid           # Small badge/snippet
├── snippets/                  # Reusable Liquid snippets
│   └── component.liquid       # Shared components
├── assets/                    # JS/CSS files
│   ├── app-embed.js           # Minimal JS (forms, interactions)
│   └── styles.css             # Scoped styles
└── locales/
    └── en.default.json        # Translations

App Block Pattern

Block Schema

liquid
1{% schema %} 2{ 3 "name": "Feature Name", 4 "target": "section", 5 "enabled_by_default": false, 6 "settings": [ 7 { 8 "type": "range", 9 "id": "items_per_page", 10 "label": "Items per page", 11 "min": 3, 12 "max": 20, 13 "default": 10 14 }, 15 { 16 "type": "color", 17 "id": "primary_color", 18 "label": "Primary color", 19 "default": "#000000" 20 } 21 ] 22} 23{% endschema %} 24 25{% comment %} Block content {% endcomment %} 26<div class="app-feature" data-resource-id="{{ product.id }}"> 27 {% render 'app-component', resource: product, settings: block.settings %} 28</div> 29 30{% stylesheet %} 31 .app-feature { /* scoped styles */ } 32{% endstylesheet %} 33 34{% javascript %} 35 // Minimal JS only when needed 36{% endjavascript %}

Block Targets

TargetUse For
sectionProduct page, collection page content
bodyGlobal elements (popups, floating buttons)

App Embed (Global Script)

For loading global CSS and minimal JS across all pages:

liquid
1{% schema %} 2{ 3 "name": "App Embed", 4 "target": "body", 5 "enabled_by_default": true, 6 "settings": [] 7} 8{% endschema %} 9 10{% comment %} Load styles globally {% endcomment %} 11{{ 'styles.css' | asset_url | stylesheet_tag }} 12 13{% comment %} Minimal JS - forms, interactions only {% endcomment %} 14<script src="{{ 'app-embed.js' | asset_url }}" defer></script> 15 16{% comment %} Pass data to JS {% endcomment %} 17<script> 18 window.APP_CONFIG = { 19 shopDomain: '{{ shop.permanent_domain }}', 20 customerId: '{{ customer.id | default: "" }}', 21 locale: '{{ request.locale.iso_code }}' 22 }; 23</script>

App Proxy Integration

Configure in shopify.app.toml

toml
1[app_proxy] 2url = "https://<firebase-url>/clientApi" 3subpath = "app-name" 4subpath_prefix = "apps"

Fetch Data via App Proxy

liquid
1{% comment %} 2 App proxy URL: /apps/app-name/endpoint 3 Shopify adds shop param automatically 4{% endcomment %} 5 6{% assign api_url = shop.url | append: '/apps/app-name/data/' | append: resource.id %}

Backend Handler

javascript
1// clientApi controller - receives 'shop' query param from app proxy 2export async function getData(ctx) { 3 const shopDomain = ctx.query.shop; 4 const {id} = ctx.params; 5 6 const shop = await shopRepository.getShopByShopifyDomain(shopDomain); 7 if (!shop) { 8 ctx.body = {success: false, error: 'Shop not found'}; 9 return; 10 } 11 12 const data = await service.getData(shop.id, id); 13 ctx.body = data; 14}

Async Data Fetching with Loading States

When blocks need dynamic data from app proxy, use loading states for good UX.

HTML Structure

liquid
1{% comment %} 2 Generic async widget pattern 3 - Unique IDs using resource ID (product, collection, page, etc.) 4 - Data attributes for JS configuration 5 - Loading/content/error states 6{% endcomment %} 7 8{% assign widget_id = product.id | default: collection.id | default: 'global' %} 9 10<div class="app-widget" 11 data-resource-id="{{ widget_id }}" 12 data-resource-type="{{ resource_type | default: 'product' }}" 13 data-shop="{{ shop.permanent_domain }}" 14 id="app-widget-{{ widget_id }}"> 15 16 <div class="app-widget__loading" id="app-loading-{{ widget_id }}"> 17 <span class="app-widget__spinner"></span> 18 {{ 'app.loading' | t | default: 'Loading...' }} 19 </div> 20 21 <div class="app-widget__content" id="app-content-{{ widget_id }}" style="display: none;"> 22 {%- comment -%} Content populated by JS {%- endcomment -%} 23 </div> 24 25 <div class="app-widget__error" id="app-error-{{ widget_id }}" style="display: none;"> 26 {{ 'app.error' | t | default: 'Unable to load content' }} 27 </div> 28</div>

JavaScript Pattern

javascript
1(function() { 2 // Configuration 3 var PROXY_PATH = '/apps/proxy'; // Your app proxy path 4 var ENDPOINT = '/data'; // Your endpoint 5 6 // Get elements 7 var containers = document.querySelectorAll('.app-widget'); 8 9 containers.forEach(function(container) { 10 var resourceId = container.dataset.resourceId; 11 var resourceType = container.dataset.resourceType; 12 var shop = container.dataset.shop; 13 14 var loadingEl = document.getElementById('app-loading-' + resourceId); 15 var contentEl = document.getElementById('app-content-' + resourceId); 16 var errorEl = document.getElementById('app-error-' + resourceId); 17 18 async function fetchData() { 19 try { 20 var params = new URLSearchParams({ 21 resource_id: resourceId, 22 resource_type: resourceType, 23 shop: shop 24 }); 25 26 var response = await fetch(PROXY_PATH + ENDPOINT + '?' + params); 27 var result = await response.json(); 28 29 if (!result.success) { 30 throw new Error(result.error || 'Request failed'); 31 } 32 33 if (!result.data) { 34 container.dataset.hidden = 'true'; 35 return; 36 } 37 38 renderContent(result.data, result.settings); 39 loadingEl.style.display = 'none'; 40 contentEl.style.display = 'block'; 41 } catch (error) { 42 console.error('Widget error:', error); 43 loadingEl.style.display = 'none'; 44 errorEl.style.display = 'block'; 45 } 46 } 47 48 function renderContent(data, settings) { 49 // Build your HTML from data 50 contentEl.innerHTML = buildHTML(data, settings); 51 } 52 53 // Initialize on DOM ready 54 if (document.readyState === 'loading') { 55 document.addEventListener('DOMContentLoaded', fetchData); 56 } else { 57 fetchData(); 58 } 59 }); 60})();

CSS Utilities

css
1/* Loading spinner */ 2.app-widget__spinner { 3 width: 16px; 4 height: 16px; 5 border: 2px solid #e5e5e5; 6 border-top-color: var(--app-accent-color, #008060); 7 border-radius: 50%; 8 animation: app-spin 0.8s linear infinite; 9} 10 11@keyframes app-spin { 12 to { transform: rotate(360deg); } 13} 14 15/* Hide widget when no data */ 16.app-widget[data-hidden="true"] { 17 display: none; 18} 19 20/* Loading state */ 21.app-widget__loading { 22 display: flex; 23 align-items: center; 24 gap: 8px; 25 padding: 16px; 26 color: #666; 27} 28 29/* Error state */ 30.app-widget__error { 31 padding: 16px; 32 color: #c00; 33 text-align: center; 34}

Key Points

AspectRecommendation
Unique IDsUse resource ID (product, collection, etc.) for uniqueness
Loading stateAlways show spinner while fetching
Error handlingShow user-friendly error, hide widget on failure
Empty stateUse data-hidden="true" to hide when no data
TranslationsUse Liquid t filter for user-facing text

Liquid-First Rendering

Server-Side Data Display

liquid
1{% comment %} Data from metafields or app proxy {% endcomment %} 2{% assign items = product.metafields.app_namespace.items.value %} 3 4{% if items.size > 0 %} 5 <div class="items-list"> 6 {% for item in items %} 7 {% render 'item-card', item: item %} 8 {% endfor %} 9 </div> 10{% else %} 11 <p class="no-items">{{ 'app.no_items' | t }}</p> 12{% endif %}

Reusable Snippets

liquid
1{% comment %} snippets/rating-display.liquid {% endcomment %} 2{% comment %} 3 @param value {number} - Value to display 4 @param max {number} - Maximum value 5 @param size {string} - 'small' | 'medium' | 'large' 6{% endcomment %} 7 8<div class="rating-display rating-display--{{ size | default: 'medium' }}"> 9 {% for i in (1..max) %} 10 {% if i <= value %} 11 <span class="rating-unit rating-unit--filled"></span> 12 {% else %} 13 <span class="rating-unit rating-unit--empty"></span> 14 {% endif %} 15 {% endfor %} 16</div>

Minimal JavaScript Pattern

When JS is Needed

Use JS ForKeep in Liquid
Form submissionStatic content display
File uploadBadges and indicators
Pagination/load moreProduct lists
Real-time validationSEO content

Minimal JS Structure

javascript
1// assets/app-embed.js 2 3(function() { 4 'use strict'; 5 6 const config = window.APP_CONFIG || {}; 7 8 // Form handling 9 function initForms() { 10 document.querySelectorAll('[data-app-form]').forEach(form => { 11 form.addEventListener('submit', handleSubmit); 12 }); 13 } 14 15 async function handleSubmit(e) { 16 e.preventDefault(); 17 const form = e.target; 18 const data = new FormData(form); 19 20 try { 21 const response = await fetch(form.action, { 22 method: 'POST', 23 body: JSON.stringify(Object.fromEntries(data)), 24 headers: {'Content-Type': 'application/json'} 25 }); 26 27 const result = await response.json(); 28 if (result.success) { 29 showMessage(form, 'success', result.data.message); 30 } else { 31 showMessage(form, 'error', result.error); 32 } 33 } catch (err) { 34 showMessage(form, 'error', 'Something went wrong'); 35 } 36 } 37 38 // Initialize when DOM ready 39 if (document.readyState === 'loading') { 40 document.addEventListener('DOMContentLoaded', initForms); 41 } else { 42 initForms(); 43 } 44})();

Translations

Locale File Structure

json
1{ 2 "app": { 3 "title": "Feature Title", 4 "submit": "Submit", 5 "success": "Submitted successfully", 6 "error": "Something went wrong", 7 "no_items": "No items yet" 8 } 9}

Using Translations

liquid
1{% comment %} In Liquid {% endcomment %} 2{{ 'app.title' | t }} 3 4{% comment %} With variables {% endcomment %} 5{{ 'app.count' | t: count: items.size }}

Performance Guidelines

Do's

PracticeWhy
Render in LiquidServer-side = faster
Use snippetsReusable, cacheable
Defer JS loadingNon-blocking
Scope CSSAvoid conflicts

Don'ts

AvoidWhy
Heavy JS frameworksBundle size
Inline stylesCache miss
Blocking scriptsSlow page load
Fetch on page loadDelays rendering

Checklist

Block Development

- Schema defines all settings
- Uses snippets for reusable parts
- Translations for all text
- Scoped CSS (no global pollution)
- Minimal/no inline JS

App Proxy Integration

- shopify.app.toml configured
- Backend validates shop parameter
- Returns JSON for JS consumption
- HTML rendering for Liquid consumption

Performance

- JS deferred or async
- CSS in stylesheet (not inline)
- Images lazy loaded
- No external dependencies
- Bundle < 20KB total

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is theme-extension?

Ideal for E-commerce Development Agents requiring server-side rendering for high-performance Shopify storefronts. theme-extension is a development approach that uses Shopify's native Liquid rendering for server-rendered content, ensuring optimal storefront performance.

How do I install theme-extension?

Run the command: npx killer-skills add ducnm-mimhus/Avada-Simple-Sales-Pop. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for theme-extension?

Key use cases include: Rendering static/semi-static content blocks, Implementing SEO-optimized product displays, Developing server-rendered theme components.

Which IDEs are compatible with theme-extension?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for theme-extension?

Not suitable for highly interactive widgets requiring real-time updates. Limited to Shopify's Liquid templating system. Requires Theme App Extension deployment structure.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add ducnm-mimhus/Avada-Simple-Sales-Pop. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use theme-extension immediately in the current project.

Related Skills

Looking for an alternative to theme-extension or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI