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
New to add-ons?
Start with the Hello, World! tutorial to create your first add-on, then return here to understand project structure. For terminology clarification, see the Developer Terminology Guide.

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:

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:

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:

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:

Characteristics:

Document sandbox path in manifest:

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

Build Templates (All Others)

These templates use webpack:

Characteristics:

Document sandbox path in manifest:

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

Why the difference?

data-variant=info
data-slots=text
For more on webpack configuration and build tools, see Frameworks, Libraries and Bundling.

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:

Where Things Go

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

UI Code (Always in iframe runtime)

Goes in:

Includes:

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

Document Manipulation Code (Only in document sandbox)

Goes in:

Includes:

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

Available APIs in document sandbox:

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 Type
CSS Location
How 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

What
No-Build
Build (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 Type
main
documentSandbox
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).

data-slots=header, text1
data-variant=info
Important
Both template types use Spectrum Web Components by default. The key difference is how you write your code (vanilla JavaScript with Lit vs. React with JSX), not which UI components you use.

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:

Features:

data-variant=info
data-slots=text
New to Lit? See the Using Lit & TypeScript Tutorial for a complete guide to building add-ons with SWC templates.

What are React Templates?

React templates use the React framework for building UI.

React templates are characterized by:

Features:

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:

Examples of good SWC template use cases:

Getting started with SWC:

When to Choose React Templates

Choose React templates if:

Examples of good React template use cases:

Side-by-Side Comparison

Aspect
SWC Templates
React 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
data-variant=info
data-slots=header, text
SWC and JS Libraries
As a developer, you can use other libraries than Lit. For example, if you are a React developer, you can use @swc-react to implement SWC components in your add-ons.

The Bottom Line

If you're new to add-on development:

If you're an experienced developer:

Learn more about Spectrum:

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

Use Case
Recommended Template
Why
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:

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
Build Tool
UI Framework
TypeScript
Doc Sandbox
Complexity
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

data-variant=info
data-slots=header, text1
Want to try SWC TypeScript templates?
Follow the Using Lit & TypeScript Tutorial for a complete walkthrough of building an add-on with the 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
Note

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:

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:

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:

Getting Started

Core Concepts

References

Examples