Add-on Project Anatomy Guide
A comprehensive guide to understanding Adobe Express add-on project structure, file organization, and template selection.
data-variant=info
data-slots=header, text1
Understanding the Basics
Every Adobe Express add-on has these essential files:
manifest.json- Tells Adobe Express about your add-onindex.html- Your add-on's user interfaceindex.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:
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:
{
"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:
- Development Tools - CLI commands and local development setup
- Manifest Reference - Complete manifest configuration guide
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.jsonpaths point directly to source files- No
webpack.config.jsfile - No
npm run buildcommand needed for development
Document sandbox path in manifest:
"documentSandbox": "sandbox/code.js" // Full path to source file
Build Templates (All Others)
These templates use webpack:
swc-javascript/swc-javascript-with-document-sandboxswc-typescript/swc-typescript-with-document-sandboxreact-javascript/react-javascript-with-document-sandboxreact-typescript/react-typescript-with-document-sandbox
Characteristics:
- Files in
src/are bundled todist/ manifest.jsonpaths point to bundled output files- Has
webpack.config.jsfile - Requires
npm run buildto generatedist/folder
Document sandbox path in manifest:
"documentSandbox": "code.js" // Just filename - webpack outputs to dist/code.js
Why the difference?
- No-build:
"sandbox/code.js"→ Adobe Express loadssrc/sandbox/code.jsdirectly - Build:
"code.js"→ Webpack bundlessrc/sandbox/code.js→ outputs todist/code.js→ Adobe Express loadsdist/code.js
data-variant=info
data-slots=text
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:
src/
├── index.html
├── index.js # All code here
└── manifest.json
With document sandbox:
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:
{
"entryPoints": [{
"type": "panel",
"main": "index.html",
"documentSandbox": "sandbox/code.js" // or "code.js" for build templates
}]
}
3. Code Split
UI code (ui/index.js):
import addOnUISdk from "https://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):
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:
- Add-on Architecture Guide - Complete communication patterns
- Communication APIs Reference - API documentation
- Stats Add-on Tutorial - Build an add-on using communication APIs
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.jsorsrc/index.jsx - Templates with sandbox:
src/ui/index.jsorsrc/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(orcode.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.) - ✅
consoleAPI - ✅
BlobAPI (limited implementation) - ✅ Express Document SDK (
editorobject) - ❌ 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.
src/styles.css<link rel="stylesheet" href="styles.css"> in index.htmlsrc/styles.css or src/ui/styles.css<link rel="stylesheet" href="styles.css"> in index.htmlsrc/components/App.css.js or .css.tssrc/components/App.cssimport './App.css' in componentShared Code
Important: Code cannot be directly shared between iframe runtime and document sandbox. Each environment is isolated.
Options:
- Duplicate code - Copy utilities into both
ui/andsandbox/folders - Pass data - Send processed data between environments via API proxy
- Types/interfaces - Can be shared in
src/models/orsrc/types/(TypeScript only)
For more on why environments are isolated, see the Iframe Runtime Context & Security Guide.
Quick Reference
File Locations Cheat Sheet
src/index.jssrc/index.jssrc/ui/index.jssrc/index.htmlsrc/index.htmlsrc/index.htmlsrc/styles.csssrc/components/App.csssrc/ui/components/App.csssrc/sandbox/code.jssrc/manifest.jsonsrc/manifest.jsonsrc/manifest.jsonsrc/ (direct)dist/dist/Manifest Path Cheat Sheet
maindocumentSandbox"index.html""index.html""sandbox/code.js""index.html""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).
data-slots=header, text1
data-variant=info
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.tsor.css.jsfiles) - 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
data-variant=info
data-slots=text
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):
// Use native web components directly
<sp-button size="m" @click=${this._handleClick}>
Create Rectangle
</sp-button>
React Templates:
// 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:
- Using Lit & TypeScript Tutorial - Step-by-step guide to building with SWC templates
- Using Adobe Spectrum Workshop - Learn Spectrum Web Components
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
<sp-button>)<Button> from @swc-react)<sp-button @click=${fn}><Button onClick={fn}>.css.ts files).css files)data-variant=info
data-slots=header, text
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:
- Using Adobe Spectrum Tutorial - Complete workshop on Spectrum Web Components
- UX Guidelines - Design principles for Adobe Express add-ons
Template Selection Guide
Quick Decision Tree
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
javascriptjavascriptjavascript-with-document-sandboxreact-javascriptreact-typescript-with-document-sandboxMigration Path
You can upgrade templates as your add-on grows:
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
Template Structure Examples
data-variant=info
data-slots=header, text1
swc-typescript-with-document-sandbox template.1. JavaScript (No Build, No Sandbox)
my-addon/
├── src/
│ ├── index.html
│ ├── index.js
│ └── manifest.json
└── tsconfig.json
2. JavaScript with Document Sandbox (No Build)
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)
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)
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
data-slots=text
data-variant=info
To see thecomplete file structures of all 10 templates, refer to the template-specific documentation or examine the scaffolded project files.
Hands-on tutorials:
- Building Your First Add-on (Grids Tutorial) - Build a complete add-on with Document APIs
- Using Lit & TypeScript - Build with SWC TypeScript template
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 todist/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 intoui/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:
- Duplicate the code in both
ui/andsandbox/folders - Pass processed data between environments via the API proxy
- Share TypeScript types/interfaces only (in
src/models/orsrc/types/)
Summary
Essential Takeaways:
- Only two templates have no build process:
javascriptandjavascript-with-document-sandbox - All other templates use webpack and output to
dist/ - UI code always goes in iframe runtime (never in document sandbox)
- CSS always goes in iframe runtime (never in document sandbox)
- Document sandbox has limited browser APIs (no DOM, no
setTimeout(), nofetch()) - Manifest paths differ between build and no-build templates
- 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 →
javascripttemplate - Need document access → add
-with-document-sandbox - Complex UI → add
react- - Type safety → add TypeScript variant
Related Documentation
Getting Started
- Hello, World! Tutorial - Create your first add-on
- Code Playground - Experiment with add-on APIs in your browser
- Development Tools - CLI commands and local development
- Adobe Express Add-on MCP Server - AI-assisted development with LLMs
Core Concepts
- Developer Terminology - Essential terminology reference
- Add-on Architecture Guide - Deep dive into dual-runtime system
References
- Manifest Reference - Complete manifest configuration
- Add-on UI SDK Reference - Add-on UI SDK APIs
- Document APIs Reference - Document manipulation APIs
Examples
- Sample Add-ons - Browse example projects