Skip to main content

Component Tiers Reference

SpiderPublish components support 4 interactivity tiers. Each tier adds capability on top of the previous one. The tier is determined automatically by which fields are present — there is no explicit "tier" field.


Comparison Table

Tier 1: StaticTier 2: InteractiveTier 3: RichTier 4: App
Fieldshtml_template + css+ js+ dependencies+ framework + source_code
JavaScriptNoneScoped vanilla JSVanilla + CDN librariesFramework (React/Vue/Svelte)
CDN LibrariesNoNoYes (allowlisted)Optional
Build StepNoneNoneNoneesbuild (async)
RenderingLiquid → Shadow DOM+ hydration script+ <script> in <head><script type="module"> + custom element
PerformanceFastestFastFast (async CDN)Slightly heavier (JS bundle)
Best ForHeroes, footers, content sectionsAccordions, tabs, counters, togglesScroll animations, carousels, charts, 3DDashboards, configurators, complex forms

Which Tier Should I Use?

Rule of thumb: Start with the lowest tier that meets your needs. Tier 1 is the fastest and simplest. Only move up when you genuinely need the extra capability.


Tier 1: Static

What: HTML template (Liquid) + CSS. No JavaScript execution.

Fields used:

  • html_template (required) — Liquid template with {{ props.* }} and {% for %} tags
  • css (optional) — Component CSS, scoped via Shadow DOM

How it renders:

  1. Liquid engine processes html_template with merged props
  2. Output wrapped in <spideriq-cmp data-slug="..."> with Declarative Shadow DOM
  3. CSS injected inside <style> within the shadow root
  4. Theme variables (:host { --primary: #...; }) auto-injected

Output HTML:

<spideriq-cmp data-slug="hero-gradient">
<template shadowrootmode="open">
<style>
:host { --primary: #2563eb; --font-body: system-ui, sans-serif; }
.hero { background: linear-gradient(135deg, var(--primary), #000); /* ... */ }
</style>
<section class="hero">
<h1>Ship Faster with AI</h1>
</section>
</template>
</spideriq-cmp>

Limitations:

  • No interactivity (no click handlers, no state changes)
  • No animations beyond CSS transitions/keyframes

When to use: Content sections, heroes, footers, feature grids, pricing tables, testimonial displays, stat bars — anything that doesn't need JS.


Tier 2: Interactive

What: Tier 1 + scoped vanilla JavaScript.

Added field:

  • js — Vanilla JS string. Executed via new Function('root','props', code)(shadowRoot, mergedProps)

How it renders:

  1. Same as Tier 1 (Liquid → Shadow DOM)
  2. JS stored as <script type="spideriq/component-js"> inside the shadow template (non-executable type)
  3. data-has-js="true" attribute added to <spideriq-cmp>
  4. A ~200-byte hydration script is injected once before </body> (shared by all Tier 2+ components on the page)
  5. Hydration script finds all data-has-js components, reads the stored JS, and executes it scoped to each shadow root

JS environment:

  • root — the ShadowRoot element. Use root.querySelector() to find elements
  • props — merged props object (block props + defaults)
  • No access to document.body, window.location, or any parent DOM
  • No import statements — vanilla JS only
  • console.log, setTimeout, fetch are available

Example (click counter):

// js field value:
const btn = root.querySelector('.counter-btn');
const display = root.querySelector('.count');
let count = props.start || 0;
display.textContent = count;
btn.addEventListener('click', () => {
count++;
display.textContent = count;
});

Limitations:

  • No external libraries (use Tier 3 for that)
  • No ES module imports
  • Must be self-contained vanilla JS

When to use: Accordions, tabs, toggle switches, copy-to-clipboard buttons, counters, form validation, dark mode toggles — anything achievable with vanilla JS event listeners and DOM manipulation.


Tier 3: Rich

What: Tier 2 + CDN library dependencies from an admin-managed allowlist.

Added field:

  • dependencies — Array of allowlist keys (e.g., ["gsap", "gsap/ScrollTrigger"])

How it renders:

  1. Same as Tier 2
  2. Dependencies resolved from content_cdn_allowlist table
  3. Library <script> tags injected in page <head> with async/defer per library's load_strategy
  4. SRI hashes applied when available
  5. Deduplicated: If 3 components on the same page all use gsap, it's loaded only once

Validation:

  • On component create/update, all dependency keys are validated against the allowlist
  • Unknown keys are rejected with a clear error message
  • Disabled libraries (is_active = false) are also rejected

Example (GSAP scroll reveal):

{
"dependencies": ["gsap", "gsap/ScrollTrigger"],
"js": "gsap.registerPlugin(ScrollTrigger); gsap.from(root.querySelector('.content'), { opacity: 0, y: 50, duration: 1, scrollTrigger: { trigger: root.querySelector('.content'), start: 'top 80%' } });"
}

Limitations:

  • Only allowlisted CDN libraries — no arbitrary <script> URLs
  • Libraries are global (loaded in <head>), but your JS still runs scoped to the shadow root
  • Contact your admin to add new libraries to the allowlist

When to use: Scroll-triggered animations (GSAP), carousels (Swiper), data visualizations (Chart.js), After Effects animations (Lottie), 3D scenes (Three.js), animated counters (CountUp), reactive UI (Alpine.js).


Tier 4: App

What: Full framework component (React, Vue, or Svelte). Source code is compiled server-side by esbuild into a self-contained Web Component bundle.

Added fields:

  • framework (required) — "react", "vue", or "svelte"
  • source_code (required) — The framework source code

Read-only fields (set by the build system):

  • bundle_url — R2 CDN URL of the compiled bundle (set on successful build)
  • build_status"none", "building", "success", or "failed"
  • build_error — Error message if build failed

How it renders:

  1. On publish: esbuild compiles source_code into a Web Component wrapper
  2. Bundle uploaded to R2: components/{client_id}/{slug}/v{version}/bundle.js
  3. On the live page: <script type="module" src="{bundle_url}"> in <head>
  4. Custom element <spideriq-app-{slug}> renders with data-props attribute
  5. The framework wrapper handles shadow root attachment, rendering, and cleanup

Build lifecycle:

POST .../publish → 202 Accepted
→ build_status: "building"
→ esbuild compiles source_code
→ Success: build_status: "success", bundle_url set
→ Failure: build_status: "failed", build_error set

Source code format:

FrameworkFormatDefault Export
ReactJSX (React 18+)export default function Name(props) { ... }
VueSFC (.vue format)<template>, <script setup>, <style scoped>
SvelteSvelte component<script>, HTML, <style>

Important: When framework is set, html_template and css are ignored — the framework source is the single source of truth.

API endpoints specific to Tier 4:

  • GET /dashboard/content/components/{id}/build-status — Poll build progress
  • POST /dashboard/content/components/{id}/rebuild — Re-trigger build after fixing source (returns 202)

Limitations:

  • Builds are async — publish returns 202, not 200
  • Larger bundles than Tier 1-3 (framework runtime included)
  • Must poll build-status before the component is usable
  • Source code must be self-contained (no relative imports from other files)

When to use: Interactive dashboards, product configurators, multi-step forms, data-heavy UIs with complex state, anything requiring React/Vue/Svelte ecosystem features.


CDN Allowlist Reference

The CDN allowlist is managed by the SpiderIQ admin. These are the currently available libraries:

KeyNameCategoryURLDescription
gsapGSAP Coreanimationcdn.jsdelivr.net/npm/gsap@3.12/dist/gsap.min.jsGreenSock animation library
gsap/ScrollTriggerGSAP ScrollTriggeranimationcdn.jsdelivr.net/npm/gsap@3.12/dist/ScrollTrigger.min.jsScroll-triggered animations
gsap/FlipGSAP Flipanimationcdn.jsdelivr.net/npm/gsap@3.12/dist/Flip.min.jsLayout transition animations
animejsanime.jsanimationcdn.jsdelivr.net/npm/animejs@3.2/lib/anime.min.jsLightweight animation library
alpinejsAlpine.jsframeworkcdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.jsMinimal reactive framework
chartjsChart.jsvisualizationcdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.jsCanvas charting library
lottieLottie Webanimationcdn.jsdelivr.net/npm/lottie-web@5/build/player/lottie_light.min.jsAfter Effects animation player
swiperSwipercarouselcdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.jsTouch slider/carousel
countupCountUp.jsanimationcdn.jsdelivr.net/npm/countup.js@2/dist/countUp.umd.jsAnimated number counter
threeThree.js3dcdn.jsdelivr.net/npm/three@0.162/build/three.module.min.jsWebGL 3D library

API Endpoints

# List all available libraries (public, no auth)
GET /api/v1/content/cdn-allowlist

# Admin CRUD (requires auth)
POST /api/v1/dashboard/content/cdn-allowlist # Add library
PATCH /api/v1/dashboard/content/cdn-allowlist/{id} # Update
DELETE /api/v1/dashboard/content/cdn-allowlist/{id} # Remove
Need a library that's not listed?

Contact your SpiderIQ admin to add it to the allowlist. Libraries must be hosted on trusted CDNs (jsdelivr, cdnjs, unpkg) and ideally have SRI hashes for security.


Security Model

SpiderPublish components are designed to be safe even when built by untrusted AI agents or third parties.

Shadow DOM Isolation

  • Every component renders inside a Declarative Shadow DOM boundary
  • Component CSS cannot leak to the parent page or other components
  • Parent page CSS cannot affect component internals
  • CSS custom properties (var(--primary)) are the only intentional bridge — they pierce Shadow DOM by design

JavaScript Scoping (Tier 2-3)

  • JS executes via new Function('root','props', code) — scoped to the shadow root
  • root is the ShadowRoot element, not document
  • No access to document.body, window.location, cookies, or localStorage from within the function scope
  • Each component instance gets its own execution context

CDN Allowlist (Tier 3)

  • Only admin-approved libraries from trusted CDNs can be loaded
  • Unknown dependency keys are rejected at create/update time
  • SRI (Subresource Integrity) hashes are enforced when available
  • Disabled libraries (is_active = false) are blocked

Framework Builds (Tier 4)

  • Source code is compiled server-side by esbuild — no arbitrary code execution in the browser at build time
  • Bundles are served from your own R2 CDN bucket
  • The Web Component wrapper provides shadow root isolation for framework output
  • No external network requests during the build process