A React library for visualizing AWS Step Functions workflows (Amazon States Language) in the browser. Built with TypeScript and based on the AWS Toolkit for VS Code.
Check out our Storybook to see interactive examples and explore all available components and features.
- 🎨 Visual Workflow Rendering - Display ASL workflows as interactive graphs
- 🌓 Theme Support - Light and dark themes built-in
- 📐 Layout Options - Support for Top-to-Bottom and Left-to-Right layouts
- ✅ ASL Validation - Comprehensive validation for ASL syntax and semantics
- 🔄 Auto Layout - Automatic graph layout with reactive updates
- 📱 Responsive - Works on different screen sizes
- 🖱️ Interactive - Click handlers for states and connections
- 🔍 Detailed Inspection - Rich state details panel with JSON viewing
- 🌐 Multiple Input Sources - Load from definition objects, URLs, or files
- 📄 YAML Support - Support for both JSON and YAML formats
- 🔧 Extensible - Easy to customize and extend
- 📚 TypeScript - Full TypeScript support with comprehensive types
npm install asl-vieweror with Yarn:
yarn add asl-viewerImportant: You must import the CSS file for the component to display correctly.
import "asl-viewer/dist/index.css";require("asl-viewer/dist/index.css");<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/asl-viewer@latest/dist/index.css"
/>If you're using CSS-in-JS libraries or have build tools that don't handle CSS imports automatically, make sure to include the CSS file in your build process or import it in your main application file.
import React from "react";
import { WorkflowViewer } from "asl-viewer";
import "asl-viewer/dist/index.css"; // Required CSS import
const workflow = {
Comment: "A simple minimal example",
StartAt: "Hello",
States: {
Hello: {
Type: "Task",
Resource: "arn:aws:lambda:us-east-1:123456789012:function:HelloWorld",
End: true,
},
},
};
function App() {
return (
<WorkflowViewer
definition={workflow}
theme="light"
width={800}
height={600}
/>
);
}import React from "react";
import { WorkflowViewer } from "asl-viewer";
import "asl-viewer/dist/index.css"; // Required CSS import
function App() {
return (
<WorkflowViewer
url="https://example.com/workflow.json"
theme="light"
width={800}
height={600}
onLoadStart={() => console.log("Loading...")}
onLoadEnd={() => console.log("Loaded!")}
onLoadError={(error) => console.error("Error:", error)}
/>
);
}import React, { useState } from "react";
import { WorkflowViewer, FileUploader } from "asl-viewer";
import "asl-viewer/dist/index.css"; // Required CSS import
function App() {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
return (
<div>
<FileUploader
onFileSelect={setSelectedFile}
theme={{
background: "white",
borderColor: "#ddd",
textColor: "#333",
infoColor: "#007acc",
}}
/>
{selectedFile && (
<WorkflowViewer
file={selectedFile}
theme="light"
width={800}
height={600}
/>
)}
</div>
);
}import React from "react";
import { WorkflowViewer } from "asl-viewer";
const yamlWorkflow = `
Comment: "A workflow in YAML format"
StartAt: "HelloWorld"
States:
HelloWorld:
Type: "Pass"
Result: "Hello from YAML!"
End: true
`;
function App() {
function App() {
return (
<WorkflowViewer
definition={yamlWorkflow}
theme="light"
width={800}
height={600}
/>
);
}import React from "react";
import { WorkflowViewer } from "asl-viewer";
function App() {
return (
<WorkflowViewer
definition={workflow}
theme="light"
width={900}
height={700}
readonly={false}
isDraggable={true}
isSelectable={true}
isMultiSelect={true}
useMiniMap={true}
useControls={true}
onStateClick={(state) => {
console.log("State clicked:", state);
}}
/>
);
}import React from "react";
import { WorkflowViewer } from "asl-viewer";
function App() {
return (
<WorkflowViewer
definition={workflow}
theme="light"
width={800}
height={600}
readonly={true}
useControls={false}
useMiniMap={false}
isDraggable={false}
isSelectable={false}
useZoom={false}
/>
);
}import React from "react";
import { WorkflowViewer } from "asl-viewer";
function App() {
return (
<WorkflowViewer
definition={complexWorkflow}
theme="dark"
width={1000}
height={800}
useMiniMap={true}
useControls={true}
useFitView={true}
useZoom={true}
/>
);
}ASL Viewer supports multiple input formats and sources:
- Definition Object: Pass ASL definition directly as JavaScript object
- URL: Load from any accessible URL (supports CORS)
- File Upload: Upload local JSON or YAML files via file picker or drag & drop
- JSON: Standard ASL format as used by AWS Step Functions
- YAML: Human-readable YAML format with same structure as JSON
The library automatically detects format based on:
- File extension (
.json,.yaml,.yml) - MIME type (
application/json,application/yaml,text/yaml) - Content analysis (fallback parsing)
# JSON format
{
"Comment": "A simple workflow",
"StartAt": "FirstState",
"States": {
"FirstState": {
"Type": "Pass",
"End": true
}
}
}
# YAML format
Comment: "A simple workflow"
StartAt: "FirstState"
States:
FirstState:
Type: "Pass"
End: true| Prop | Type | Default | Description |
|---|---|---|---|
definition |
ASLDefinition | string |
- | The ASL workflow definition (JSON or YAML) |
url |
string |
- | URL to load the ASL definition from |
file |
File |
- | File object containing the ASL definition |
theme |
'light' | 'dark' |
'light' |
Visual theme |
layoutDirection |
'TB' | 'LR' |
'TB' |
Layout direction (Top-Bottom or Left-Right) |
width |
number |
800 |
Viewer width in pixels |
height |
number |
600 |
Viewer height in pixels |
readonly |
boolean |
true |
Whether the viewer is read-only |
isConnectable |
boolean |
true |
Whether nodes can be connected |
isDraggable |
boolean |
false |
Whether nodes can be dragged |
isSelectable |
boolean |
true |
Whether nodes can be selected |
isMultiSelect |
boolean |
false |
Whether multiple nodes can be selected |
useMiniMap |
boolean |
false |
Whether to show navigation minimap |
useControls |
boolean |
true |
Whether to show zoom/pan controls |
useZoom |
boolean |
true |
Whether zooming is enabled |
useFitView |
boolean |
true |
Whether to auto-fit view to show all nodes |
showToolbar |
boolean |
false |
Whether to show the toolbar |
hideComment |
boolean |
false |
Whether to hide the workflow comment |
onStateClick |
(state: StateNode) => void |
- | Callback when a state is clicked |
onValidationError |
(error: ValidationError) => void |
- | Callback for validation errors |
onLoadStart |
() => void |
- | Callback when loading starts |
onLoadEnd |
() => void |
- | Callback when loading completes |
onLoadError |
(error: Error) => void |
- | Callback when loading fails |
className |
string |
- | Additional CSS class names |
style |
React.CSSProperties |
- | Inline styles for the root container |
Note: You must provide exactly one of definition, url, or file.
Enable full interactivity with draggable nodes, multi-selection, and comprehensive controls:
<WorkflowViewer
definition={workflow}
readonly={false}
isDraggable={true}
isSelectable={true}
isMultiSelect={true}
useMiniMap={true}
useControls={true}
onStateClick={(state) => console.log("Clicked:", state)}
/>Perfect for presentations or documentation with minimal UI:
<WorkflowViewer
definition={workflow}
readonly={true}
useControls={false}
useMiniMap={false}
isDraggable={false}
isSelectable={false}
useZoom={false}
/>Ideal for complex workflows with enhanced navigation features:
<WorkflowViewer
definition={largeWorkflow}
useMiniMap={true}
useControls={true}
useFitView={true}
useZoom={true}
width={1000}
height={800}
/>Display the workflow from left to right instead of top to bottom:
<WorkflowViewer
definition={workflow}
layoutDirection="LR"
width={1000}
height={600}
/>Compact view for embedding in dashboards or smaller spaces:
<WorkflowViewer
definition={simpleWorkflow}
width={400}
height={300}
useControls={false}
useMiniMap={false}
useFitView={true}
/>| Prop | Type | Default | Description |
|---|---|---|---|
onFileSelect |
(file: File) => void |
required | Callback when a file is selected |
theme |
ViewerTheme |
required | Theme object for styling |
accept |
string |
".json,.yaml,.yml" |
File types to accept |
disabled |
boolean |
false |
Whether the uploader is disabled |
className |
string |
- | Additional CSS class names |
style |
React.CSSProperties |
- | Inline styles |
| Prop | Type | Default | Description |
|---|---|---|---|
onUrlSubmit |
(url: string) => void |
required | Callback when URL is submitted |
theme |
ViewerTheme |
required | Theme object for styling |
disabled |
boolean |
false |
Whether the input is disabled |
placeholder |
string |
"Enter URL to ASL definition..." |
Placeholder text |
className |
string |
- | Additional CSS class names |
style |
React.CSSProperties |
- | Inline styles |
import type {
ASLDefinition,
StateDefinition,
StateType,
ValidationError,
WorkflowViewerProps,
ViewerTheme,
StateNode,
} from "asl-viewer";import {
validateASLDefinition,
parseASLDefinition,
createGraphLayout,
loadFromURL,
loadFromFile,
parseDefinitionString,
} from "asl-viewer";
// Validate an ASL definition
const errors = validateASLDefinition(workflow);
// Load from URL
const workflowFromUrl = await loadFromURL("https://example.com/workflow.json");
// Load from file
const workflowFromFile = await loadFromFile(file);
// Parse string (JSON or YAML)
const workflowFromString = parseDefinitionString(yamlOrJsonString);
// Parse and get structured data
const parsed = parseASLDefinition(workflow);
// Create custom layout
const layout = createGraphLayout(parsed.nodes, parsed.connections);- ✅ Task States - Lambda functions, activities, and other tasks
- ✅ Choice States - Conditional branching with choice rules
- ✅ Pass States - Data transformation and flow control
- ✅ Wait States - Delays and timeouts
- ✅ Succeed/Fail States - Terminal states
- ✅ Parallel States - Concurrent execution branches
- ✅ Map States - Iteration over arrays (basic support)
- ✅ Retry/Catch - Error handling configuration
- ✅ Input/Output Processing - Path expressions and filters
Control user interactions with the workflow:
// Enable all interactive features
<WorkflowViewer
definition={workflow}
readonly={false}
isDraggable={true} // Drag nodes around
isSelectable={true} // Click to select nodes
isMultiSelect={true} // Select multiple nodes
isConnectable={true} // Connect nodes (if applicable)
/>
// Read-only with selection only
<WorkflowViewer
definition={workflow}
readonly={true}
isSelectable={true}
isDraggable={false}
isMultiSelect={false}
/>Configure zoom, pan, and navigation features:
// Full navigation controls
<WorkflowViewer
definition={workflow}
useControls={true} // Show zoom/pan buttons
useZoom={true} // Enable zoom functionality
useFitView={true} // Auto-fit content to view
useMiniMap={true} // Show minimap for navigation
/>
// Minimal navigation
<WorkflowViewer
definition={workflow}
useControls={false}
useZoom={false}
useFitView={true}
useMiniMap={false}
/>Handle user interactions and loading events:
<WorkflowViewer
definition={workflow}
onStateClick={(state) => {
console.log("State clicked:", state.name, state.type);
// Handle state selection, show details, etc.
}}
onValidationError={(error) => {
console.error("Validation error:", error.message);
// Handle validation errors
}}
onLoadStart={() => {
console.log("Loading workflow...");
// Show loading indicator
}}
onLoadEnd={() => {
console.log("Workflow loaded successfully");
// Hide loading indicator
}}
onLoadError={(error) => {
console.error("Failed to load workflow:", error);
// Show error message
}}
/>Check out the /examples directory for complete usage examples:
git clone <repository>
cd asl-viewer
yarn installyarn buildRun Storybook locally for development:
yarn storybookBuild Storybook for production:
yarn build-storybookThe Storybook is automatically deployed to GitHub Pages at https://cleissonb.github.io/asl-viewer/ when changes are pushed to the main branch.
yarn testimport { WorkflowViewer, getTheme } from "asl-viewer";
import "asl-viewer/dist/index.css"; // Don't forget the CSS import
const customTheme = {
...getTheme("light"),
nodeColors: {
...getTheme("light").nodeColors,
taskState: "#ff6b6b",
choiceState: "#4ecdc4",
},
};
<WorkflowViewer definition={workflow} theme={customTheme} />;import { WorkflowViewer, createCustomTheme } from "asl-viewer";
import "asl-viewer/dist/index.css"; // Don't forget the CSS import
const customPurple = createCustomTheme("dark", {
name: "customPurple",
background: "#1a0033",
surfaceColor: "#2d1b69",
nodeColors: {
task: "#4c1d95",
choice: "#7c2d12",
succeed: "#065f46",
},
nodeBorderColors: {
task: "#8b5cf6",
choice: "#f59e0b",
succeed: "#10b981",
},
textColor: "#e879f9",
connectionColor: "#c084fc",
tooltipBackground: "#3c004d",
tooltipTextColor: "#f0f0f0",
});
<WorkflowViewer definition={workflow} theme={customPurple} />;- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes
- Add tests for new functionality
- Run the test suite:
yarn test - Submit a pull request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
