Edit in GitHubLog an issue

Handle Element Selection

Learn how to work with user selections, handle selection changes, and create responsive interfaces that react to what users select in their Adobe Express documents.

Getting Started with Selections

Selections in Adobe Express represent the elements (nodes) that users have currently selected in their document. The selection system provides access to what's selected, the ability to change selections programmatically, and events to respond to selection changes.

All selection operations use the Document API and run in the document sandbox environment. This means your selection code should be placed in your code.js file, not in your main iframe panel code.

Quick Start Example

Copied to your clipboard
// sandbox/code.js
import { editor } from "express-document-sdk";
// Check if anything is selected
if (editor.context.hasSelection) {
console.log(`Selected ${editor.context.selection.length} item(s)`);
} else {
console.log("Nothing is selected");
}

Understanding Selections

In Adobe Express, the selection system provides:

  • Current selection access - Get what's currently selected
  • Selection modification - Programmatically change selections
  • Selection events - React to selection changes
  • Selection filtering - Handle locked/non-editable content

The selection system automatically enforces constraints like artboard boundaries and hierarchy rules. See the Best Practices & Guidelines section for complete details on selection rules and restrictions.

Basic Selection Operations

Core operations for working with selections.

Getting the Current Selection

Copied to your clipboard
// sandbox/code.js
import { editor } from "express-document-sdk";
// Get the current selection
const selection = editor.context.selection;
console.log("Selected nodes:", selection.length);
// Process each selected node
selection.forEach((node, index) => {
console.log(`Node ${index + 1}: ${node.type}`);
// Common node properties you can access
console.log(" Position:", node.translation);
console.log(" Size:", { width: node.width, height: node.height });
});

Programmatic Selection

Copied to your clipboard
// sandbox/code.js
import { editor } from "express-document-sdk";
// Create and select a single element
const rectangle = editor.createRectangle();
rectangle.width = 100;
rectangle.height = 100;
rectangle.translation = { x: 50, y: 50 };
// Add to document
editor.context.insertionParent.children.append(rectangle);
// Select the rectangle (single element)
editor.context.selection = rectangle;
// OR using array syntax: editor.context.selection = [rectangle];
console.log("Rectangle is now selected");

Multiple Selection

Copied to your clipboard
// sandbox/code.js
import { editor } from "express-document-sdk";
// Create multiple elements
const rectangle = editor.createRectangle();
rectangle.width = 80;
rectangle.height = 80;
rectangle.translation = { x: 50, y: 50 };
const ellipse = editor.createEllipse();
ellipse.rx = 40;
ellipse.ry = 40;
ellipse.translation = { x: 200, y: 50 };
// Add both to document
const parent = editor.context.insertionParent;
parent.children.append(rectangle, ellipse);
// Select both elements at once
editor.context.selection = [rectangle, ellipse];
console.log("Multiple elements selected:", editor.context.selection.length);

Clearing the Selection

Copied to your clipboard
// sandbox/code.js
import { editor } from "express-document-sdk";
// Clear the selection - both ways work
editor.context.selection = [];
// OR: editor.context.selection = undefined;
console.log("Selection cleared");
console.log("Has selection:", editor.context.hasSelection); // false

Selection Events

Respond to selection changes to create dynamic UIs that update based on what's selected.

Basic Selection Change Handler

Copied to your clipboard
// sandbox/code.js
import { editor, EditorEvent } from "express-document-sdk";
// Listen for selection changes
const handlerId = editor.context.on(EditorEvent.selectionChange, () => {
const selection = editor.context.selection;
console.log("Selection changed!");
console.log("New selection count:", selection.length);
if (selection.length === 0) {
console.log("Nothing selected");
} else if (selection.length === 1) {
console.log("One item selected:", selection[0].type);
} else {
console.log("Multiple items selected");
}
});
// Store handlerId if you need to unregister later
console.log("Selection handler registered:", handlerId);

Properties Panel Example

Dynamic properties panel based on selection:

Copied to your clipboard
// sandbox/code.js
import { editor, EditorEvent } from "express-document-sdk";
function updatePropertiesPanel() {
const selection = editor.context.selection;
if (selection.length === 0) {
console.log("Properties Panel: Show 'Nothing Selected' state");
return;
}
if (selection.length === 1) {
const node = selection[0];
console.log("Properties Panel: Show properties for", node.type);
// Show different properties based on node type
if (node.type === "Text") {
console.log(" - Show font controls");
console.log(" - Show text color picker");
} else if (node.type === "Rectangle" || node.type === "Ellipse") {
console.log(" - Show fill color picker");
console.log(" - Show stroke controls");
}
// Common properties for all nodes
console.log(" - Show position controls");
console.log(" - Show size controls");
} else {
console.log("Properties Panel: Show multi-selection options");
console.log(` - ${selection.length} items selected`);
console.log(" - Show alignment tools");
console.log(" - Show group option");
}
}
// Register the handler
editor.context.on(EditorEvent.selectionChange, updatePropertiesPanel);
// Call once on startup to initialize
updatePropertiesPanel();

Event Handler Cleanup

⚠️ Important: Always clean up event handlers to prevent memory leaks.

Copied to your clipboard
// sandbox/code.js
import { editor, EditorEvent } from "express-document-sdk";
// Store handler IDs so you can unregister them later
let selectionHandlerId = null;
function startListening() {
// Register handler and store the ID
selectionHandlerId = editor.context.on(EditorEvent.selectionChange, () => {
console.log("Selection changed!");
// Handle selection change
});
console.log("✅ Selection handler registered");
}
function stopListening() {
// Clean up the handler
if (selectionHandlerId) {
editor.context.off(EditorEvent.selectionChange, selectionHandlerId);
selectionHandlerId = null;
console.log("✅ Selection handler cleaned up");
}
}
// Start listening
startListening();
// Clean up when your add-on is being destroyed or reset
// stopListening();

Advanced Selection Techniques

Advanced patterns for complex add-ons.

Working with Locked/Non-Editable Elements

Handle selections that include locked or non-editable content:

Copied to your clipboard
// sandbox/code.js
import { editor, EditorEvent } from "express-document-sdk";
function analyzeCompleteSelection() {
const selection = editor.context.selection;
const fullSelection = editor.context.selectionIncludingNonEditable;
return {
editableCount: selection.length,
totalCount: fullSelection.length,
lockedCount: fullSelection.length - selection.length,
types: [...new Set(selection.map(node => node.type))], // Unique types
hasText: selection.some(node => node.type === "Text"),
hasShapes: selection.some(node =>
node.type === "Rectangle" || node.type === "Ellipse"
),
isEmpty: !editor.context.hasSelection
};
}
// Example: Dynamic UI updates based on detailed analysis
editor.context.on(EditorEvent.selectionChange, () => {
const analysis = analyzeCompleteSelection();
console.log("📊 Detailed Selection Info:");
console.log(` Editable: ${analysis.editableCount}`);
if (analysis.lockedCount > 0) {
console.log(` Locked: ${analysis.lockedCount}`);
}
console.log(` Types: ${analysis.types.join(", ")}`);
// Enable specific tools based on content
if (analysis.hasText) {
console.log("🔤 Text formatting tools available");
}
if (analysis.hasShapes) {
console.log("🔷 Shape styling tools available");
}
if (analysis.editableCount > 1) {
console.log("📐 Alignment tools available");
}
});

Practical Selection Patterns

Real-world patterns for building selection-based features in your add-on.

Performing Actions on Selected Elements

Common patterns for applying changes to selected elements:

Copied to your clipboard
// sandbox/code.js
import { editor, colorUtils } from "express-document-sdk";
// Function to apply red color to selected text
function applyRedToSelectedText() {
const selection = editor.context.selection;
// Filter for text nodes only
const textNodes = selection.filter(node => node.type === "Text");
if (textNodes.length === 0) {
console.log("No text nodes selected");
return;
}
// Apply red color to all selected text
const redColor = colorUtils.fromHex("#FF0000");
textNodes.forEach(textNode => {
textNode.fullContent.applyCharacterStyles({ color: redColor });
});
console.log(`Applied red color to ${textNodes.length} text nodes`);
}
// Function to group selected elements
function groupSelection() {
const selection = editor.context.selection;
if (selection.length < 2) {
console.log("Need at least 2 elements to create a group");
return;
}
// Create a group
const group = editor.createGroup();
// Add selected elements to the group
selection.forEach(node => {
// Remove from current parent and add to group
node.removeFromParent();
group.children.append(node);
});
// Add group to the document
editor.context.insertionParent.children.append(group);
// Select the new group
editor.context.selection = group;
console.log(`Created group with ${selection.length} elements`);
}
// Register handlers for different actions
editor.context.on(EditorEvent.selectionChange, () => {
const selection = editor.context.selection;
// Update UI or enable/disable actions based on selection
if (selection.length === 0) {
console.log("No selection - disable all actions");
} else if (selection.length === 1) {
console.log("Single selection - enable individual actions");
} else {
console.log("Multiple selection - enable group actions");
}
});

Advanced: Selection State Management

Track selection history and manage complex selection states:

Copied to your clipboard
// sandbox/code.js
import { editor, EditorEvent } from "express-document-sdk";
class SelectionManager {
constructor() {
this.selectionHistory = [];
this.handlerId = null;
this.startListening();
}
startListening() {
this.handlerId = editor.context.on(EditorEvent.selectionChange, () => {
const selection = editor.context.selection;
// Store selection in history (limit to last 10)
this.selectionHistory.push([...selection]);
if (this.selectionHistory.length > 10) {
this.selectionHistory.shift();
}
console.log("Selection history length:", this.selectionHistory.length);
this.notifySelectionChange(selection);
});
}
notifySelectionChange(selection) {
// Custom logic based on selection
if (selection.length === 0) {
this.onNoSelection();
} else if (selection.length === 1) {
this.onSingleSelection(selection[0]);
} else {
this.onMultipleSelection(selection);
}
}
onNoSelection() {
console.log("No elements selected");
// Disable context-sensitive UI
}
onSingleSelection(node) {
console.log("Single element selected:", node.type);
// Enable single-element actions
}
onMultipleSelection(selection) {
console.log("Multiple elements selected:", selection.length);
// Enable multi-element actions
}
restorePreviousSelection() {
if (this.selectionHistory.length >= 2) {
const previousSelection = this.selectionHistory[this.selectionHistory.length - 2];
editor.context.selection = previousSelection;
}
}
stopListening() {
if (this.handlerId) {
editor.context.off(EditorEvent.selectionChange, this.handlerId);
this.handlerId = null;
}
}
}
// Usage
const selectionManager = new SelectionManager();

Best Practices & Guidelines

Selection Handler Restrictions

Selection System Rules

Adobe Express enforces these constraints:

  1. Artboard constraint: Only nodes within the current artboard can be selected
  2. Hierarchy filtering: Cannot select both parent and child nodes simultaneously
  3. Locked node handling: Locked nodes are excluded from main selection but available in selectionIncludingNonEditable
  4. Automatic filtering: System automatically filters out invalid selections

Performance Guidelines

  1. Keep handlers fast: Minimize processing time and avoid heavy computations in selection callbacks
  2. Essential work only: Only perform UI updates, logging, or data analysis in selection handlers
  3. Always clean up: Unregister event handlers when done using editor.context.off() to prevent memory leaks

Communicating with Your UI Panel

To create responsive interfaces, you'll need to communicate selection changes from the document sandbox to your UI panel. This allows you to update buttons, property panels, and other UI elements based on what the user has selected.

For complete details on setting up bidirectional communication between your document sandbox and UI panel, see the Communication API reference.

Quick Reference

Common Selection Operations

Copied to your clipboard
// Get current selection
const selection = editor.context.selection;
// Check if anything is selected
if (editor.context.hasSelection) { /* ... */ }
// Select a single element
editor.context.selection = node;
// Select multiple elements
editor.context.selection = [node1, node2, node3];
// Clear selection
editor.context.selection = [];
// Get selection including locked nodes
const fullSelection = editor.context.selectionIncludingNonEditable;

Selection Event Handling

Copied to your clipboard
// Register selection change handler
const handlerId = editor.context.on(EditorEvent.selectionChange, () => {
const selection = editor.context.selection;
// Handle selection change
});
// Clean up handler
editor.context.off(EditorEvent.selectionChange, handlerId);

Common Selection Patterns

Copied to your clipboard
// Access first selected element
const node = editor.context.selection[0];
// Filter selection by type
const textNodes = selection.filter(node => node.type === "Text");
// Check selection count
if (selection.length === 0) { /* nothing selected */ }
if (selection.length === 1) { /* single selection */ }
if (selection.length > 1) { /* multiple selection */ }
// Check for specific node types
const hasText = selection.some(node => node.type === "Text");
const hasShapes = selection.some(node =>
["Rectangle", "Ellipse"].includes(node.type)
);

FAQs

Q: How do I get the current selection?

A: Use editor.context.selection to get an array of currently selected nodes.

Q: How do I listen for selection changes?

A: Use editor.context.on(EditorEvent.selectionChange, callback) to register a selection change handler.

Q: How do I programmatically select elements?

A: Set editor.context.selection = node for single elements or editor.context.selection = [node1, node2] for multiple elements.

Q: What's the difference between selection and selectionIncludingNonEditable?

A: selection only includes editable nodes, while selectionIncludingNonEditable also includes locked/non-editable nodes.

Q: Can I modify the document in a selection change callback?

A: No, avoid making document changes in selection change callbacks as it may destabilize the application.

Q: How do I clear the selection?

A: Set editor.context.selection = [] or editor.context.selection = undefined.

Q: What are the selection rules?

A: Nodes must be within the current artboard, ancestors cannot be selected with descendants, and locked nodes are filtered out.

Q: How do I unregister selection event handlers?

A: Use editor.context.off(EditorEvent.selectionChange, handlerId) with the ID returned from the on() method.

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