ESC
Start typing to search documentation...
JoonWeb DEV
Category Overview

Theme & Section Skills

Build custom JoonWeb (.jw) sections and layouts using conversational AI models, ChatGPT, Claude, and Cursor.

Theme & Section Skills Overview

Build custom JoonWeb (.jw) sections and layouts using conversational AI models, ChatGPT, Claude, and Cursor.

3 Endpoints / Guides • Official Developer Specification
AI Section Studio & Universal Skills

Build Custom .jw Sections with AI

Use our official jw-theme-sections skill to generate responsive, error-free storefront sections in ChatGPT, Claude, Cursor, and AI coding agents.

View SKILL.md
1. Select Your AI Platform
ChatGPT Workflow: Click "1-Click Launch in ChatGPT" below to open ChatGPT with the pre-loaded prompt and skill context. Alternatively, create a Custom GPT with the system instructions below.
2. Choose a Section Example / Preset Switch presets to test different prompt types & outputs
Ready-to-Run Prompt Hero Banner
You are an Expert JoonWeb Theme Developer. Follow the official JoonWeb section specifications from:
https://joonweb.dev/skills/jw-theme-sections/SKILL.md

Generate a production-ready Hero Banner section in .jw format with:
- Top comment: {# Copy and paste this code directly into the JoonWeb Theme Editor (.jw file) #}
- Strict file order: Variables {% set %} -> <style> -> <section> -> <script> -> {% rules %}
- Scoped CSS under {{ S }} MUST be placed BEFORE <section>
- Conditionals using != '' or 'is not empty' (never != blank)
- Outer wrapper with data-bl="{{ site ? 0 : 1 }}", data-xx="1", and background{{ sc }}
- Editable blocks using data-jw-block
- Valid schema types only (radio yes/no, quickEditor, text, image_picker, range)
- Append {"type": "themes"} and {"type": "apps"} to schema blocks
- Populated presets with realistic default blocks (NEVER include themes or apps in presets)
- Right above rules schema comment: {# Do not change if you don't know #}
- No bulky or decorative divider comments
Expected .jw File Structure (Pure JW Language + Bootstrap 5.3 + Populated Presets)
{# Copy and paste this code directly into the JoonWeb Theme Editor (.jw file) #}

{% set ss = section.settings %}
{% set S  = '#jw-section-' ~ section.id %}
{% set sc = (section.colors  | default('5')) | replace({ 'background': '' }) %}
{% set bg_col   = ss.customBg == 'yes' ? ss.bgColor | default('') : '' %}
{% set text_col = ss.customText == 'yes' ? ss.textColor | default('') : '' %}
{% set card_bg  = ss.customCardBg == 'yes' ? ss.cardBgColor | default('') : '' %}
{% set card_tx  = ss.customCardText == 'yes' ? ss.cardTextColor | default('') : '' %}
{% set width_map = { "full-width": "full-width", "container": "container", "container-fluid": "container-fluid" } %}
{% set width = width_map[ss.sectionWidth] ?? 'container' %}
{% set v = ss.image is iterable ? (ss.image.src ?? ss.image.url ?? ss.image.value ?? '') : (ss.image ?? '') %}
{% set img = v != '' ? ((v starts with 'http' or v starts with '/' or v starts with 'data:') ? v : v | asset_url) : '' %}

<style>
  {{ S }} {
    padding-top: var(--pad-t);
    padding-bottom: var(--pad-b);
    position: relative;
    overflow: hidden;
  }
  {{ S }} .hb-badge {
    background: rgba(59, 130, 246, 0.12);
    color: #2563eb;
    border: 1px solid rgba(59, 130, 246, 0.25);
    font-size: 0.75rem;
    letter-spacing: 0.05em;
  }
  {{ S }} .hb-img {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  }
  {{ S }} .hb-media-wrap:hover .hb-img {
    transform: scale(1.03);
  }
  {{ S }}.hb-ccbg .hb-card { background: var(--ccbg) !important; }
  {{ S }}.hb-cctx .hb-card { color: var(--cctx) !important; }

  @media (max-width: 749.98px){
    {{ S }} {
      padding-top: calc(var(--pad-t) * 0.7);
      padding-bottom: calc(var(--pad-b) * 0.7);
    }
  }

  /* Builder Overrides */
  {{ S }}[data-bl="1"] .hb-img { transform: none !important; }
  @media (prefers-reduced-motion: reduce){
    {{ S }} * { animation: none !important; transition: none !important; }
  }
</style>

<section
  id="jw-section-{{ section.id }}"
  class="hb background{{ sc }} {{ card_bg != '' ? 'hb-ccbg' : '' }} {{ card_tx != '' ? 'hb-cctx' : '' }}"
  data-xx="1" data-bl="{{ site ? 0 : 1 }}"
  style="{{ bg_col != '' ? 'background:' ~ bg_col ~ ';' : '' }} {{ text_col != '' ? 'color:' ~ text_col ~ ';' : '' }} {{ card_bg != '' ? '--ccbg:' ~ card_bg ~ ';' : '' }} {{ card_tx != '' ? '--cctx:' ~ card_tx ~ ';' : '' }} --pad-t: {{ ss.pad_top | default(80) }}px; --pad-b: {{ ss.pad_bottom | default(80) }}px;">

  <div class="{{ width }}" data-id="{{ section.id }}">
    <div class="row align-items-center g-5 {{ ss.reverse_mobile == 'yes' ? 'flex-column-reverse flex-lg-row' : '' }}">
      <div class="col-12 col-lg-6">
        <div class="hb-content text-{{ ss.alignment | default('left') }}">
          {% for block in section.blocks ?? [] %}
            {% set b = block.settings %}
            {% switch block.type %}
              {% case "badge" %}
                <div class="hb-blk mb-3" data-jw-block>
                  <span class="badge rounded-pill px-3 py-2 text-uppercase fw-bold hb-badge">
                    {{ b.text | default('New Season') }}
                  </span>
                </div>

              {% case "heading" %}
                <div class="hb-blk mb-3" data-jw-block>
                  <h1 class="display-4 fw-bold mb-0 lh-tight hb-title fontStyle1">
                    {{ (b.text ?? 'Digital Storefront Innovation') | raw }}
                  </h1>
                </div>

              {% case "text" %}
                <div class="hb-blk mb-4" data-jw-block>
                  <div class="lead mb-0 hb-desc fontStyle7">
                    {{ (b.content ?? '<p>High-converting, responsive storefront architecture built natively with JW Language.</p>') | raw }}
                  </div>
                </div>

              {% case "buttons" %}
                <div class="hb-blk mb-4" data-jw-block>
                  <div class="d-flex flex-wrap gap-3 align-items-center {{ ss.alignment == 'center' ? 'justify-content-center' : '' }}">
                    {% set btn1_url = b.btn1_link is iterable ? (b.btn1_link.url ?? '') : (b.btn1_link ?? '') %}
                    {% if btn1_url != '' %}
                      <a href="{{ btn1_url }}" class="btn btn-primary px-4 py-3 rounded-pill fw-bold shadow-sm">
                        <span>{{ b.btn1_text | default('Explore Catalog') }}</span>
                        <i class="bi bi-arrow-right ms-2"></i>
                      </a>
                    {% endif %}
                    {% set btn2_url = b.btn2_link is iterable ? (b.btn2_link.url ?? '') : (b.btn2_link ?? '') %}
                    {% if btn2_url != '' %}
                      <a href="{{ btn2_url }}" class="btn btn-outline-secondary px-4 py-3 rounded-pill fw-bold">
                        <span>{{ b.btn2_text | default('Learn More') }}</span>
                      </a>
                    {% endif %}
                  </div>
                </div>

              {% default %}
                {{ render_block(block) }}
            {% endswitch %}
          {% endfor %}
        </div>
      </div>

      <div class="col-12 col-lg-6">
        <div class="hb-media-wrap position-relative">
          {% if img != '' %}
            <div class="hb-img-frame rounded-4 overflow-hidden shadow-lg">
              <img src="{{ img }}" alt="{{ ss.heading | default('Hero Banner') | striptags }}" class="img-fluid w-100 hb-img" loading="lazy" onerror="this.onerror=null;this.src='https://images.unsplash.com/photo-1441986300917-64674bd600d8?auto=format&fit=crop&w=1200&q=80';">
            </div>
          {% else %}
            <div class="hb-placeholder rounded-4 d-flex align-items-center justify-content-center text-muted p-5 bg-light">
              <i class="bi bi-image fs-1 me-2"></i>
              <span>Select an image in section settings</span>
            </div>
          {% endif %}
        </div>
      </div>
    </div>
  </div>
</section>

<script>
(function () {
  function init(sec) {
    if (sec._hbInit) return;
    sec._hbInit = true;
    var bl = sec.getAttribute('data-bl') === '1';
    if (bl) return;
  }
  function scan() { document.querySelectorAll('[data-xx="1"]').forEach(init); }
  if (window.JWHeroBanner) { window.JWHeroBanner.scan(); return; }
  window.JWHeroBanner = { scan: scan };
  if (document.readyState !== 'loading') scan();
  else document.addEventListener('DOMContentLoaded', scan);
})();
</script>

{# Do not change if you don't know #}
{% rules %}
{
  "name": "Hero Banner",
  "settings": [
    { "type": "select", "id": "sectionWidth", "label": "Container Width", "options": [
      { "value": "container", "label": "Container" },
      { "value": "container-fluid", "label": "Container Fluid" },
      { "value": "full-width", "label": "Full Width" }
    ], "default": "container" },
    { "type": "select", "id": "alignment", "label": "Alignment", "options": [
      { "value": "left", "label": "Left" },
      { "value": "center", "label": "Center" }
    ], "default": "left" },
    { "type": "radio", "id": "reverse_mobile", "label": "Reverse on Mobile", "options": [
      { "value": "yes", "label": "Yes" }, { "value": "no", "label": "No" }
    ], "default": "no" },
    { "type": "image_picker", "id": "image", "label": "Hero Image" },
    { "type": "range", "id": "pad_top", "label": "Top Spacing", "min": 20, "max": 160, "step": 5, "unit": "px", "default": 80 },
    { "type": "range", "id": "pad_bottom", "label": "Bottom Spacing", "min": 20, "max": 160, "step": 5, "unit": "px", "default": 80 },
    { "type": "header", "content": "Custom Colors" },
    { "type": "radio", "id": "customBg", "label": "Custom Background", "options": [
      { "value": "yes", "label": "On" }, { "value": "no", "label": "Off" }
    ], "default": "no" },
    { "type": "color_background", "id": "bgColor", "label": "Background Color" },
    { "type": "radio", "id": "customText", "label": "Custom Text Color", "options": [
      { "value": "yes", "label": "On" }, { "value": "no", "label": "Off" }
    ], "default": "no" },
    { "type": "color", "id": "textColor", "label": "Text Color" }
  ],
  "blocks": [
    { "type": "badge", "name": "Badge Pill", "settings": [{ "type": "text", "id": "text", "label": "Text", "default": "New Arrival" }] },
    { "type": "heading", "name": "Heading", "settings": [{ "type": "text", "id": "text", "label": "Heading", "default": "Next-Generation Digital Storefronts" }] },
    { "type": "text", "name": "Description", "settings": [{ "type": "quickEditor", "id": "content", "label": "Content", "default": "<p>Build high-converting storefronts with JW Language architecture.</p>" }] },
    { "type": "buttons", "name": "Buttons", "settings": [
      { "type": "text", "id": "btn1_text", "label": "Primary Button Text", "default": "Shop New Arrivals" },
      { "type": "url", "id": "btn1_link", "label": "Primary Button Link" }
    ] },
    { "type": "themes" },
    { "type": "apps" }
  ],
  "presets": [
    {
      "name": "Hero Banner",
      "category": "Hero",
      "settings": { "colors": "5", "alignment": "left", "pad_top": 80, "pad_bottom": 80 },
      "blocks": [
        { "type": "badge", "settings": { "text": "✨ Spring 2026 Collection" } },
        { "type": "heading", "settings": { "text": "Next-Generation Digital Storefronts" } },
        { "type": "text", "settings": { "content": "<p>Build high-converting storefronts with JW Language architecture.</p>" } },
        { "type": "buttons", "settings": { "btn1_text": "Shop New Arrivals" } }
      ]
    }
  ]
}
{% endrules %}
Last updated: Oct 12, 2026