Edit in GitHubLog an issue

Add-on Project Anatomy Guide

A comprehensive guide to understanding Adobe Express add-on project structure, file organization, and template selection.

Understanding the Basics

Every Adobe Express add-on has these essential files:

  1. manifest.json - Tells Adobe Express about your add-on
  2. index.html - Your add-on's user interface
  3. index.js - Your add-on's logic

The complexity grows based on:

  • Whether you need to create/modify document content (requires document sandbox)
  • Whether you use a build tool (webpack)
  • Whether you use a UI framework (React) or TypeScript

See the Add-on Architecture Guide for a deep dive into how these pieces work together.

The Simplest Add-on

Plain JavaScript Template (No Build)

This is the absolute simplest structure - no build tools, no document manipulation:

Copied to your clipboard
my-addon/
├── src/
│ ├── index.html # Your UI
│ ├── index.js # Your UI logic
│ └── manifest.json # Configuration
├── tsconfig.json # For IDE support only
└── README.md

Characteristics:

  • ✅ No build process - files are used directly as-is
  • ✅ Perfect for learning
  • ✅ Great for simple UI-only add-ons
  • ❌ Cannot create/modify document content
  • ❌ No modern JavaScript features (no JSX, no imports beyond basic ES modules)

manifest.json:

Copied to your clipboard
{
"entryPoints": [{
"type": "panel",
"main": "index.html"
}]
}

When to use: Simple tools like settings panels, calculators, reference guides, or anything that doesn't need to create shapes/text/images in the document.

Related guides:

Build vs. No-Build Templates

Understanding the difference between build and no-build templates is essential for working with add-on projects:

No-Build Templates

Only two templates have no build process:

  • javascript (UI-only)
  • javascript-with-document-sandbox (with document manipulation)

Characteristics:

  • Files in src/ are used directly
  • manifest.json paths point directly to source files
  • No webpack.config.js file
  • No npm run build command needed for development

Document sandbox path in manifest:

Copied to your clipboard
"documentSandbox": "sandbox/code.js" // Full path to source file

Build Templates (All Others)

These templates use webpack:

  • swc-javascript / swc-javascript-with-document-sandbox
  • swc-typescript / swc-typescript-with-document-sandbox
  • react-javascript / react-javascript-with-document-sandbox
  • react-typescript / react-typescript-with-document-sandbox

Characteristics:

  • Files in src/ are bundled to dist/
  • manifest.json paths point to bundled output files
  • Has webpack.config.js file
  • Requires npm run build to generate dist/ folder

Document sandbox path in manifest:

Copied to your clipboard
"documentSandbox": "code.js" // Just filename - webpack outputs to dist/code.js

Why the difference?

  • No-build: "sandbox/code.js" → Adobe Express loads src/sandbox/code.js directly
  • Build: "code.js" → Webpack bundles src/sandbox/code.js → outputs to dist/code.js → Adobe Express loads dist/code.js

Adding Document Manipulation

When your add-on needs to create or modify document content (shapes, text, images), you need the document sandbox.

What Changes?

1. Folder Structure

Without document sandbox:

Copied to your clipboard
src/
├── index.html
├── index.js # All code here
└── manifest.json

With document sandbox:

Copied to your clipboard
src/
├── index.html
├── manifest.json
├── ui/ # UI code moves here
│ ├── index.js
│ └── tsconfig.json
└── sandbox/ # Document code goes here
├── code.js
└── tsconfig.json

2. Manifest Configuration

Add the documentSandbox property:

Copied to your clipboard
{
"entryPoints": [{
"type": "panel",
"main": "index.html",
"documentSandbox": "sandbox/code.js" // or "code.js" for build templates
}]
}

3. Code Split

UI code (ui/index.js):

Copied to your clipboard
import addOnUISdk from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
addOnUISdk.ready.then(async () => {
// Get proxy to communicate with document sandbox
const sandboxProxy = await addOnUISdk.instance.runtime.apiProxy("documentSandbox");
// UI interactions
document.getElementById("createBtn").addEventListener("click", async () => {
await sandboxProxy.createRectangle(); // Call document sandbox
});
});

Document sandbox code (sandbox/code.js):

Copied to your clipboard
import addOnSandboxSdk from "add-on-sdk-document-sandbox";
import { editor } from "express-document-sdk";
const { runtime } = addOnSandboxSdk.instance;
runtime.exposeApi({
createRectangle: () => {
const rectangle = editor.createRectangle();
rectangle.width = 240;
rectangle.height = 180;
editor.context.insertionParent.children.append(rectangle);
}
});

Learn more about communication:

Where Things Go

Here's the definitive guide for organizing your add-on code:

UI Code (Always in iframe runtime)

Goes in:

  • No-build templates: src/index.js
  • Build templates without sandbox: src/index.js or src/index.jsx
  • Templates with sandbox: src/ui/index.js or src/ui/index.jsx

Includes:

  • ✅ HTML manipulation (document.getElementById, etc.)
  • ✅ CSS and styling
  • ✅ User input handling (forms, buttons, clicks)
  • ✅ Add-on UI SDK calls (dialogs, OAuth, exports)
  • ✅ Network requests (fetch, API calls)
  • ✅ Communication with document sandbox

See the Add-on UI SDK Reference for complete API documentation.

Document Manipulation Code (Only in document sandbox)

Goes in:

  • src/sandbox/code.js (or code.ts)

Includes:

  • ✅ Creating shapes, text, images
  • ✅ Modifying document content
  • ✅ Reading document properties
  • ✅ Express Document SDK operations
  • ❌ NO DOM access
  • ❌ NO styling
  • ❌ NO HTML manipulation

See the Document APIs Reference for complete API documentation and the Document API Concepts Guide for detailed explanations.

Available APIs in document sandbox:

  • ✅ Standard JavaScript built-ins (Date, Math, JSON, etc.)
  • console API
  • Blob API (limited implementation)
  • ✅ Express Document SDK (editor object)
  • ❌ NO setTimeout() / setInterval()
  • ❌ NO fetch() / XMLHttpRequest
  • ❌ NO DOM APIs

For the complete list of available Web APIs, see the Web APIs Reference.

CSS/Styling

Always goes in iframe runtime, never in document sandbox.

Template TypeCSS LocationHow to Use
javascript
src/styles.css
<link rel="stylesheet" href="styles.css"> in index.html
javascript-with-document-sandbox
src/styles.css or src/ui/styles.css
<link rel="stylesheet" href="styles.css"> in index.html
swc-javascript/typescript
src/components/App.css.js or .css.ts
CSS-in-JS: imported in component
react-javascript/typescript
src/components/App.css
import './App.css' in component

Shared Code

Important: Code cannot be directly shared between iframe runtime and document sandbox. Each environment is isolated.

Options:

  1. Duplicate code - Copy utilities into both ui/ and sandbox/ folders
  2. Pass data - Send processed data between environments via API proxy
  3. Types/interfaces - Can be shared in src/models/ or src/types/ (TypeScript only)

For more on why environments are isolated, see the Iframe Runtime Context & Security Guide.

Quick Reference

File Locations Cheat Sheet

WhatNo-BuildBuild (No Sandbox)Build (With Sandbox)
UI Logic
src/index.js
src/index.js
src/ui/index.js
HTML
src/index.html
src/index.html
src/index.html
CSS
src/styles.css
src/components/App.css
src/ui/components/App.css
Document Code
N/A
N/A
src/sandbox/code.js
Manifest
src/manifest.json
src/manifest.json
src/manifest.json
Output
src/ (direct)
dist/
dist/

Manifest Path Cheat Sheet

Template TypemaindocumentSandbox
No-build, no sandbox
"index.html"
N/A
No-build, with sandbox
"index.html"
"sandbox/code.js"
Build, no sandbox
"index.html"
N/A
Build, with sandbox
"index.html"
"code.js"

Understanding UI Options: SWC vs. React

When choosing a template with a build process, you have two main UI approaches: SWC templates (vanilla JavaScript) or React templates (React framework).

What are SWC Templates?

SWC stands for Spectrum Web Components - Adobe's implementation of the Spectrum design system as web components.

SWC templates are characterized by:

  • Vanilla JavaScript (no UI framework like React)
  • Lit for creating custom web components
  • Native Spectrum Web Components (<sp-button>, <sp-theme>, etc.)
  • CSS-in-JS (styles written in .css.ts or .css.js files)
  • Webpack for bundling

Features:

  • ✅ Use native web components directly (<sp-button>)
  • ✅ Smaller bundle sizes (no React framework)
  • ✅ Standards-based web components
  • ✅ Great for developers who prefer vanilla JavaScript
  • ✅ Spectrum design system built-in
  • ❌ Requires learning Lit and web component patterns
  • ❌ Less familiar if you're coming from React

What are React Templates?

React templates use the React framework for building UI.

React templates are characterized by:

  • React framework for component-based UI
  • React wrappers for Spectrum Web Components (<Button>, <Theme> from @swc-react)
  • JSX syntax for writing components
  • Standard CSS files (.css)
  • Webpack for bundling

Features:

  • ✅ Familiar React patterns (hooks, JSX, component lifecycle)
  • ✅ Use Spectrum Web Components via React wrappers (@swc-react)
  • ✅ Huge React ecosystem and community
  • ✅ Great for complex UIs with lots of state
  • ✅ Spectrum design system built-in
  • ❌ Larger bundle sizes (includes React framework)
  • ❌ Requires learning React if you're new to it

The Real Difference

Both templates give you Spectrum Web Components, but they differ in how you use them:

SWC Templates (Vanilla JS):

Copied to your clipboard
// Use native web components directly
<sp-button size="m" @click=${this._handleClick}>
Create Rectangle
</sp-button>

React Templates:

Copied to your clipboard
// Use React wrappers from @swc-react
<Button size="m" onClick={handleClick}>
Create Rectangle
</Button>

The choice is really about: Do you prefer vanilla JavaScript/Lit or React?

When to Choose SWC Templates

Choose SWC templates if:

  • ✅ You want to use Adobe's Spectrum design system out of the box
  • ✅ You prefer vanilla JavaScript over frameworks
  • ✅ You're building a simple to medium complexity UI
  • ✅ You want pre-built accessible components (<sp-button>, <sp-textfield>, etc.)
  • ✅ You're comfortable with web components and Lit
  • ✅ Your team doesn't already use React
  • ✅ You want smaller bundle sizes

Examples of good SWC template use cases:

  • Settings panels with forms
  • Tools that use standard UI components (buttons, inputs, dropdowns)
  • Add-ons that should match Adobe Express's look and feel
  • Simple to medium complexity interfaces
  • Projects where accessibility is a priority (Spectrum components are accessible by default)

Getting started with SWC:

When to Choose React Templates

Choose React templates if:

  • ✅ You or your team already knows React
  • ✅ You're building a complex UI with lots of state
  • ✅ You need rich component ecosystems (many React libraries available)
  • ✅ You want familiar development patterns (hooks, JSX, etc.)
  • ✅ Your add-on has multiple views or complex workflows

Examples of good React template use cases:

  • Multi-step wizards or workflows
  • Data visualization tools
  • Complex forms with validation
  • Add-ons with multiple panels or views
  • Projects where you want to use React UI libraries

Side-by-Side Comparison

AspectSWC TemplatesReact Templates
Framework
Vanilla JS + Lit
React
Spectrum Components
Native web components (<sp-button>)
React wrappers (<Button> from @swc-react)
Design System
✅ Spectrum built-in
✅ Spectrum built-in
Component Syntax
<sp-button @click=${fn}>
<Button onClick={fn}>
Bundle Size
Smaller (no framework)
Larger (includes React)
Learning Curve
Learn Lit + web components
Learn React (if new)
UI Complexity
Simple to Medium
Medium to Complex
Ecosystem
Spectrum Web Components
React + Spectrum
Styling
CSS-in-JS (.css.ts files)
Standard CSS (.css files)
State Management
Lit reactive properties
React hooks/state
Accessibility
✅ Built-in (Spectrum)
✅ Built-in (Spectrum)
Developer Experience
Standards-based
Familiar React patterns

The Bottom Line

If you're new to add-on development:

  • Start with plain JavaScript template (no build) to learn the basics
  • Move to SWC JavaScript when you need a build tool but want simplicity
  • Move to React JavaScript if you need complex UI or already know React

If you're an experienced developer:

  • Use SWC templates for performance and simplicity
  • Use React templates if React is your comfort zone or you need complex UIs

Learn more about Spectrum:

Template Selection Guide

Quick Decision Tree

Copied to your clipboard
Do you need to create/modify document content?
├─ NO → Do you need a complex UI?
│ │
│ ├─ NO → Use: javascript
│ │
│ └─ YES → Does your team use TypeScript?
│ │
│ ├─ NO → Use: react-javascript
│ └─ YES → Use: react-typescript
└─ YES → Do you need a complex UI?
├─ NO → Does your team use TypeScript?
│ │
│ ├─ NO → Use: javascript-with-document-sandbox
│ └─ YES → Use: swc-typescript-with-document-sandbox
└─ YES → Does your team use TypeScript?
├─ NO → Use: react-javascript-with-document-sandbox
└─ YES → Use: react-typescript-with-document-sandbox

Recommendations by Use Case

Use CaseRecommended TemplateWhy
Learning add-on development
javascript
Simplest, no build tools
Simple utility (calculator, converter)
javascript
No unnecessary complexity
Creating shapes/text in document
javascript-with-document-sandbox
Adds document manipulation
Complex UI with forms/visualizations
react-javascript
React handles complex UIs well
Enterprise add-on with document manipulation
react-typescript-with-document-sandbox
Full type safety and features
Team familiar with TypeScript
Any TypeScript variant
Leverage existing skills
Need fast build times
SWC variants
SWC is faster than Babel

Migration Path

You can upgrade templates as your add-on grows:

Copied to your clipboard
javascript
↓ (add document manipulation)
javascript-with-document-sandbox
↓ (add build tools)
swc-javascript-with-document-sandbox
↓ (add React)
react-javascript-with-document-sandbox
↓ (add TypeScript)
react-typescript-with-document-sandbox

Template Comparison

Visual Comparison Matrix

TemplateBuild ToolUI FrameworkTypeScriptDoc SandboxComplexity
javascript
❌ None
Vanilla JS
⭐ Simplest
javascript-with-document-sandbox
❌ None
Vanilla JS
⭐⭐
swc-javascript
✅ Webpack
Vanilla JS
⭐⭐
swc-javascript-with-document-sandbox
✅ Webpack
Vanilla JS
⭐⭐⭐
swc-typescript
✅ Webpack
Vanilla JS
⭐⭐⭐
swc-typescript-with-document-sandbox
✅ Webpack
Vanilla JS
⭐⭐⭐⭐
react-javascript
✅ Webpack
React
⭐⭐⭐
react-javascript-with-document-sandbox
✅ Webpack
React
⭐⭐⭐⭐
react-typescript
✅ Webpack
React
⭐⭐⭐⭐
react-typescript-with-document-sandbox
✅ Webpack
React
⭐⭐⭐⭐⭐ Most complex

Template Structure Examples

1. JavaScript (No Build, No Sandbox)

Copied to your clipboard
my-addon/
├── src/
│ ├── index.html
│ ├── index.js
│ └── manifest.json
└── tsconfig.json

2. JavaScript with Document Sandbox (No Build)

Copied to your clipboard
my-addon/
├── src/
│ ├── index.html
│ ├── manifest.json
│ ├── sandbox/
│ │ ├── code.js
│ │ └── tsconfig.json
│ └── ui/
│ ├── index.js
│ └── tsconfig.json
└── tsconfig.json

3. SWC JavaScript with Document Sandbox (Build)

Copied to your clipboard
my-addon/
├── src/
│ ├── index.html
│ ├── manifest.json
│ ├── models/
│ │ └── DocumentSandboxApi.ts # Type definitions
│ ├── sandbox/
│ │ ├── code.js
│ │ └── tsconfig.json
│ └── ui/
│ ├── components/
│ │ ├── App.css.js
│ │ └── App.js
│ ├── index.js
│ └── tsconfig.json
├── tsconfig.json
└── webpack.config.js

4. React TypeScript with Document Sandbox (Build)

Copied to your clipboard
my-addon/
├── src/
│ ├── index.html
│ ├── manifest.json
│ ├── models/
│ │ └── DocumentSandboxApi.ts # Type definitions
│ ├── sandbox/
│ │ ├── code.ts
│ │ └── tsconfig.json
│ └── ui/
│ ├── components/
│ │ ├── App.css
│ │ └── App.tsx
│ ├── index.tsx
│ └── tsconfig.json
├── tsconfig.json
└── webpack.config.js

To see thecomplete file structures of all 10 templates, refer to the template-specific documentation or examine the scaffolded project files.

Hands-on tutorials:

FAQs

Q: Why does my manifest say documentSandbox: 'sandbox/code.js' but the template has code.js?

A: It depends on whether you're using a build tool:

  • No-build (javascript-with-document-sandbox): "documentSandbox": "sandbox/code.js" - points to source file
  • Build templates (all others): "documentSandbox": "code.js" - webpack bundles to dist/code.js

Q: Where do I put my CSS files?

A: Always in the iframe runtime, never in document sandbox. See the CSS/Styling section above for specific locations by template type.

Q: Why can't I use document.getElementById() in my document sandbox code?

A: The document sandbox has NO access to the DOM. See the Document Manipulation Code section above for the complete list of available and unavailable APIs.

Q: Do I need both index.js and ui/index.js?

A: No, it's one or the other:

  • Without document sandbox: Use src/index.js
  • With document sandbox: Use src/ui/index.js (code is organized into ui/ folder)

Q: Why do I have tsconfig.json if I'm using JavaScript?

A: TypeScript config files provide IDE support (IntelliSense, autocomplete, error checking) even in JavaScript projects. You get better developer experience without needing to learn TypeScript.

Q: Can I share utility functions between UI and document sandbox?

A: Not directly - each environment is isolated. You have three options:

  1. Duplicate the code in both ui/ and sandbox/ folders
  2. Pass processed data between environments via the API proxy
  3. Share TypeScript types/interfaces only (in src/models/ or src/types/)

Summary

Essential Takeaways:

  1. Only two templates have no build process: javascript and javascript-with-document-sandbox
  2. All other templates use webpack and output to dist/
  3. UI code always goes in iframe runtime (never in document sandbox)
  4. CSS always goes in iframe runtime (never in document sandbox)
  5. Document sandbox has limited browser APIs (no DOM, no setTimeout(), no fetch())
  6. Manifest paths differ between build and no-build templates
  7. Start simple and upgrade as your add-on grows in complexity

When in doubt:

  • UI/styling → iframe runtime
  • Document manipulation → document sandbox
  • Simple add-on → javascript template
  • Need document access → add -with-document-sandbox
  • Complex UI → add react-
  • Type safety → add TypeScript variant

Getting Started

Core Concepts

References

Examples

  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2025 Adobe. All rights reserved.