npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@adobe-commerce/aio-experience-kit

v1.0.3

Published

A comprehensive TypeScript toolkit for building Adobe Commerce Admin UI extensions with React Spectrum components. Provides production-ready components and utilities for Adobe I/O extensibility platform integration.

Readme

@adobe-commerce/aio-experience-kit

Overview

A TypeScript toolkit for building Adobe Commerce Admin UI extensions with React Spectrum components. This library provides production-ready components and utilities that integrate seamlessly with Adobe's I/O extensibility platform.

Key Benefits:

  • Rapid Development: Pre-built components reduce development time from weeks to days
  • Adobe Design Consistency: All components follow Adobe Spectrum design principles
  • Enterprise Ready: Built-in accessibility, internationalization, and performance optimizations
  • Developer Experience: Full TypeScript support with intelligent code completion
  • Extensible Architecture: Modular design allows for easy customization and extension
  • Production Tested: Battle-tested components used in real Adobe Commerce extensions

Installation

Install the TypeScript library with custom React components using React Spectrum:

npm install @adobe-commerce/aio-experience-kit

Usage

The toolkit is organized into two main modules:

⚛️ React Components

A collection of specialized React components built on Adobe React Spectrum, designed for creating consistent and accessible admin interfaces.

MainContainer

The main layout component for Adobe Commerce admin extensions. Provides flexible layouts with integrated navigation, routing, and responsive design.

import { MainContainer, LayoutOptions, NavigationOptions } from '@adobe-commerce/aio-experience-kit';
import { Text } from '@adobe/react-spectrum';
import HomeIcon from "@spectrum-icons/workflow/Home"
import BookIcon from "@spectrum-icons/workflow/Book"

const LibraryApp = (props) => {
  const navigationButtons = [
    {
      label: "Home",
      path: "/",
      icon: <HomeIcon size={"S"} gridArea="Home" />
    }, {
      label: "Books",
      path: "/book/grid",
      icon: <BookIcon size={"S"} gridArea="Books" />
    }
  ];

  const appRoutes = [
    {
      paths: ['/'],
      component: <Text>Home</Text>
    }, {
      paths: ['/book/:component/', '/book/:component/:id'],
      component: <Text>Books</Text>
    }
  ];

  return (
    <MainContainer
      title="Library Application"
      titleLevel={1}
      buttons={navigationButtons}
      routes={appRoutes}
      navigation={NavigationOptions.NavigationButtons}
      layout={LayoutOptions.OneColumn}
    />
  );
};

Features:

  • Flexible Layouts: Choose between OneColumn for focused content or TwoColumnLeft for navigation-heavy interfaces
  • Smart Navigation: Integrated navigation system supporting both link-based and button-based patterns
  • Routing Integration: Seamless React Router integration with automatic route matching and component rendering
  • Responsive Design: Automatically adapts to different screen sizes while maintaining usability
  • Customizable Spacing: Fine-grained control over padding, margins, and component spacing
  • Accessibility First: Built-in keyboard navigation, screen reader support, and focus management

DataTable

A powerful data grid component for displaying and managing tabular data with advanced features like sorting, selection, and bulk operations.

import React, { useState } from 'react';
import { View, ActionButton, Text } from '@adobe/react-spectrum';
import { DataTable, useRouteParams } from '@adobe-commerce/aio-experience-kit';
import AddCircle from '@spectrum-icons/workflow/AddCircle';

const EntityGrid = ({ actionCallHeaders }) => {
  const { getNavigate } = useRouteParams();
  const navigate = getNavigate();

  const [isProcessing, setProcessing] = useState(false);
  const [gridData, setGridData] = useState([]);
  
  const entityModel = new EntityModel(actionCallHeaders);
  const columns = entityModel.columns();

  const buttons = [
    <ActionButton
      variant="primary"
      type="button"
      marginEnd="size-150"
      isDisabled={isProcessing}
      onPress={() => {
        navigate('/entity/form');
      }}
    >
      <AddCircle gridArea="Create Entity" />
      <Text>Create Entity</Text>
    </ActionButton>
  ];

  const gridActions = [
    { key: 'edit', text: 'Edit' },
    { key: 'delete', text: 'Delete' }
  ];

  const massActions = [
    { key: 'delete', text: 'Delete' }
  ];

  return (
    <DataTable
      columns={columns}
      data={gridData}
      buttons={buttons}
      gridActions={gridActions}
      massActions={massActions}
      isProcessing={isProcessing}
      onMassActionPress={async (key, ids) => {
        switch (key) {
          case 'delete':
            // Process mass delete
            break;
        }
      }}
      onGridActionPress={async (key, item) => {
        switch (key) {
          case 'edit':
            navigate(`/entity/form/${item.id}`);
            break;
          case 'delete':
            // Process single delete
            break;
        }
      }}
      onGridLoad={async () => {
        setGridData(await entityModel.list());
      }}
    />
  );
};

// Entity Model
class EntityModel {
  constructor(actionCallHeaders) {
    this.actionCallHeaders = actionCallHeaders;
  }

  async list() {
    // Load data using API
    return [];
  }

  columns() {
    return [
      { name: 'Name', uid: 'name' },
      { name: 'Status', uid: 'status' },
      { name: 'Created At', uid: 'created_at' },
      { name: 'Updated At', uid: 'updated_at' },
      { name: 'Actions', uid: 'actions' }
    ];
  }
}

Vertical Scrolling for Large Datasets (v1.0.3+):

Control table height with automatic scrolling:

<DataTable
  columns={columns}
  data={largeDataset}
  maxHeight="size-6000" // Spectrum token (480px)
  // or maxHeight="500px"  // CSS value
  // or maxHeight="60vh"   // Viewport height
  onGridLoad={async () => {
    // Load large dataset
  }}
/>

Features:

  • Advanced Data Management: Sortable columns with intelligent data type handling and custom sort functions
  • Flexible Selection: Support for single-row selection or multi-row selection with visual feedback
  • Bulk Operations: Mass action system for performing operations on multiple selected items
  • Contextual Actions: Per-row actions with customizable button layouts, links, or dropdown menus
  • State Management: Built-in loading states, empty state handling, and error boundary support
  • Performance Optimized: Virtual scrolling for large datasets with efficient re-rendering
  • Scrollable Tables: Optional maxHeight prop for vertical scrolling with large datasets (v1.0.3+)
  • User Experience: Intuitive interactions with hover states, keyboard navigation, and clear visual hierarchy

DataForm

A dynamic form builder that creates forms from configuration objects with built-in validation and multiple field types.

import React, { useState } from 'react';
import { DataForm, useRouteParams, FieldType } from '@adobe-commerce/aio-experience-kit';
import { ToastQueue } from '@react-spectrum/toast';

const EntityForm = ({ actionCallHeaders, id = undefined }) => {
  const entityModel = new EntityModel(actionCallHeaders);
  
  const [formFields, setFormFields] = useState({});
  const [editItem, setEditItem] = useState({});
  
  const { getNavigate } = useRouteParams();
  const navigate = getNavigate();

  return (
    <DataForm
      components={formFields}
      editItem={editItem}
      onFormLoad={async () => {
        // Load edit item first
        let editItem = {};
        if (id !== undefined) {
          editItem = await entityModel.load(id);
          setEditItem(editItem);
        }
        // Then load form fields
        const formFields = entityModel.fields(editItem);
        setFormFields(formFields);
      }}
      onFormSubmit={async (values) => {
        try {
          await entityModel.save(values);
          ToastQueue.positive('Entity saved successfully', { timeout: 5000 });
        } catch (e) {
          ToastQueue.negative(e.message, { timeout: 5000 });
        }
      }}
      onPostFormSubmit={() => {
        navigate('/entity/grid');
      }}
      onBackPress={() => {
        navigate('/entity/grid');
      }}
    />
  );
};

// Entity Model
class EntityModel {
  constructor(actionCallHeaders) {
    this.actionCallHeaders = actionCallHeaders;
  }

  async load(id) {
    // Load entity using API
    return {};
  }

  async save(formValues) {
    // Save entity using API
    return [];
  }

  fields(editItem) {
    return {
      groups: [
        {
          code: 'entity_settings',
          label: 'Entity Settings',
          fields: [
            {
              label: 'Name',
              code: 'name',
              db_field: 'name',
              type: FieldType.TEXT,
              required: true
            },
            {
              label: 'Status',
              code: 'status',
              db_field: 'status',
              type: FieldType.SELECT,
              required: true,
              options: [
                {
                  value: '1',
                  label: 'Enabled'
                },
                {
                  value: '0',
                  label: 'Disabled'
                }
              ]
            },
            {
              label: 'Categories',
              code: 'categories',
              db_field: 'categories',
              type: FieldType.MULTISELECT,
              required: false,
              options: [
                {
                  value: 'electronics',
                  label: 'Electronics'
                },
                {
                  value: 'clothing',
                  label: 'Clothing'
                },
                {
                  value: 'books',
                  label: 'Books'
                },
                {
                  value: 'home',
                  label: 'Home & Garden'
                }
              ]
            },
            {
              label: 'Featured Product',
              code: 'featured',
              db_field: 'featured',
              type: FieldType.TOGGLE,
              required: false
            },
            {
              label: 'Notifications',
              code: 'notifications',
              db_field: 'notifications',
              type: FieldType.TOGGLE,
              required: false,
              use_env_var: true
            }
          ]
        }
      ]
    };
  }
}
Field Types

The DataForm component supports various field types for different input scenarios:

Basic Input Fields:

  • FieldType.TEXT - Standard text input
  • FieldType.EMAIL - Email input with validation
  • FieldType.PASSWORD - Password input with masking
  • FieldType.NUMBER - Numeric input with validation
  • FieldType.URL - URL input with validation
  • FieldType.TEL - Telephone number input
  • FieldType.SEARCH - Search input with appropriate styling

Selection Fields:

  • FieldType.SELECT - Single selection dropdown with options
  • FieldType.MULTISELECT - Multiple selection with checkboxes in a scrollable container
  • FieldType.TOGGLE - Boolean toggle switch with '1'/'0' values

Display Fields:

  • FieldType.LABEL - Read-only display field for showing values

Field Configuration Examples:

// MULTISELECT field with scrollable options
{
  label: 'Product Categories',
  code: 'categories',
  db_field: 'categories',
  type: FieldType.MULTISELECT,
  required: false,
  options: [
    { value: 'electronics', label: 'Electronics' },
    { value: 'clothing', label: 'Clothing' },
    { value: 'books', label: 'Books' },
    { value: 'home', label: 'Home & Garden' },
    // ... more options (automatically scrollable when many)
  ]
}

// TOGGLE field with automatic default value
{
  label: 'Enable Feature',
  code: 'feature_enabled',
  db_field: 'feature_enabled',
  type: FieldType.TOGGLE,
  required: false
  // Automatically defaults to '0' if no value provided
  // Returns '1' when enabled, '0' when disabled
}

// Field with environment variable support
{
  label: 'API Endpoint',
  code: 'api_endpoint',
  db_field: 'api_endpoint',
  type: FieldType.TEXT,
  required: true,
  use_env_var: true  // Adds checkbox to use as environment variable
}

Features:

  • Dynamic Form Generation: Create complex forms from simple configuration objects without manual field creation
  • Rich Field Types: Support for text, email, password, number, select, multiselect, toggle, and specialized input types
  • Multi-Selection Support: MULTISELECT field type with React Spectrum CheckboxGroup for selecting multiple options with scrollable overflow and accessibility support
  • Toggle Controls: TOGGLE field type using React Spectrum Switch component with '1'/'0' value handling and automatic default value initialization
  • Environment Variable Support: Built-in support for environment variable checkboxes on compatible field types (TEXT, SELECT, MULTISELECT, TOGGLE)
  • Intelligent Validation: Built-in validation with custom rules, real-time feedback, and error messaging
  • Workflow Integration: Loading states, processing indicators, and navigation controls for multi-step workflows
  • Organized Layout: Logical field grouping with collapsible sections and intuitive information hierarchy
  • Developer Friendly: Event-driven architecture with lifecycle hooks for custom business logic integration

ConfirmationDialog

A modal dialog component for user confirmations with customizable actions and styling. Perfect for delete confirmations and critical user decisions.

import React, { useState } from 'react';
import { View, ActionButton, Text } from '@adobe/react-spectrum';
import { DataTable, useRouteParams, ConfirmationDialog } from '@adobe-commerce/aio-experience-kit';

const EntityGrid = ({ actionCallHeaders }) => {
  const { getNavigate } = useRouteParams();
  const navigate = getNavigate();
  const [isProcessing, setProcessing] = useState(false);
  const [gridData, setGridData] = useState([]);
  const [deleteMessage, setDeleteMessage] = useState('');
  const [deleteKeys, setDeleteKeys] = useState([]);
  
  const entityModel = new EntityModel(actionCallHeaders);

  return (
    <View>
      <DataTable
        // ... other DataTable props
        onMassActionPress={async (key, ids) => {
          switch (key) {
            case 'delete':
              setDeleteKeys(ids);
              setDeleteMessage(`Are you sure you want to delete ${ids.length} selected items?`);
              break;
          }
        }}
        onGridActionPress={async (key, item) => {
          switch (key) {
            case 'delete':
              setDeleteKeys([item.id]);
              setDeleteMessage(`Are you sure you want to delete "${item.name}"?`);
              break;
          }
        }}
      />

      <ConfirmationDialog
        title="Delete Dialog"
        message={deleteMessage}
        primaryButtonVariant="negative"
        onDismiss={() => {
          setDeleteMessage('');
        }}
        onSecondaryPress={() => {
          setDeleteMessage('');
        }}
        onPrimaryPress={async () => {
          setDeleteMessage('');
          setProcessing(true);
          setGridData(await entityModel.delete(deleteKeys));
          setProcessing(false);
        }}
      />
    </View>
  );
};

// Entity Model
class EntityModel {
  constructor(actionCallHeaders) {
    this.actionCallHeaders = actionCallHeaders;
  }

  async delete(itemIds = []) {
    // Delete entity using API
    return [];
  }
}

Features:

  • Flexible Content: Customizable title, message, and button text to match any confirmation scenario
  • Action Variants: Support for different button styles (primary, secondary, negative) to indicate action severity
  • User Experience: Intuitive keyboard navigation with escape key dismissal and tab order management
  • Accessibility Excellence: Full screen reader support, proper ARIA labels, and focus trap implementation
  • Design Consistency: Follows Adobe Spectrum design patterns for familiar user interactions

FileUpload

A flexible file upload component with file validation and automatic content reading. Built on React Spectrum's FileTrigger for consistent Adobe design patterns.

import React, { useState } from 'react';
import { View } from '@adobe/react-spectrum';
import { FileUpload } from '@adobe-commerce/aio-experience-kit';
import { ToastQueue } from '@react-spectrum/toast';

const DocumentUploader = () => {
  const [isProcessing, setProcessing] = useState(false);

  return (
    <View>
      <FileUpload
        label="Upload Documents"
        isRequired={true}
        acceptedFileTypes={['application/pdf', '.doc', '.docx']}
        allowsMultiple={true}
        isDisabled={isProcessing}
        onSelect={async (files) => {
          setProcessing(true);
          try {
            // Process each file
          } catch (error) {
            ToastQueue.negative(`Upload failed: ${error.message}`, { timeout: 5000 });
          } finally {
            setProcessing(false);
          }
        }}
      />
    </View>
  );
};

Programmatic Control with Refs (v1.0.3+):

Reset the component programmatically from parent components:

import React, { useRef } from 'react';
import { FileUpload, FileUploadHandle } from '@adobe-commerce/aio-experience-kit';

const MyForm = () => {
  const fileUploadRef = useRef<FileUploadHandle>(null);
  
  const handleReset = () => {
    fileUploadRef.current?.reset(); // Clear all files
  };
  
  const handleGetFiles = () => {
    const files = fileUploadRef.current?.getFiles(); // Get current files
    console.log('Current files:', files);
  };
  
  return (
    <>
      <FileUpload
        ref={fileUploadRef}
        label="Upload Files"
        onSelect={(files) => console.log('Selected:', files)}
      />
      <Button onPress={handleReset}>Reset</Button>
      <Button onPress={handleGetFiles}>Get Files</Button>
    </>
  );
};

Features:

  • File Selection: Click to browse files with support for single or multiple file selection
  • Automatic Content Reading: Automatically reads file content as text or base64 based on file type
  • File Type Validation: Built-in validation for accepted MIME types and file extensions
  • Built-in Display: Automatically displays selected files with name, size, and type information
  • Clear Functionality: Built-in "Clear Files" link to remove selected files and programmatic reset via ref
  • Imperative Handle: Access reset() and getFiles() methods via React refs for parent control
  • Loading States: Shows processing indicator while reading file contents
  • Error Handling: Comprehensive error messaging for file reading failures
  • Accessibility: Full keyboard navigation, screen reader support, and ARIA labels
  • Type Safety: Complete TypeScript support with FileInfo interface for processed files

🔧 Utils

Utility functions and classes that simplify common tasks in Adobe Commerce extension development.

AdminUiSdk

A utility class for managing Adobe IMS credentials in Adobe Admin UI extensions. Provides secure access to authentication tokens and organization IDs for API calls.

Note: As of v1.0.2, registration methods have been removed. Use the Adobe UIX SDK directly for extension registration.

Getting Adobe IMS Credentials

Retrieve authentication credentials from the Adobe shared context:

import { AdminUiSdk } from '@adobe-commerce/aio-experience-kit';

try {
  const sdk = new AdminUiSdk('my_admin_extension');

  const credentials = await sdk.getCredentials();
  
  if (credentials.imsToken && credentials.imsOrgId) {
    // Use credentials for API calls
    const apiHeaders = {
      'Authorization': `Bearer ${credentials.imsToken}`,
      'x-gw-ims-org-id': credentials.imsOrgId
    };
    
    // Make authenticated API requests
  } else {
    console.log('Credentials not available');
  }
} catch (error) {
  console.error('Failed to get credentials:', error.message);
}

Features:

  • Credential Management: Secure access to Adobe IMS authentication tokens and organization IDs
  • Shared Context Access: Retrieves credentials from Adobe's shared context using @adobe/uix-guest
  • Error Handling: Comprehensive error handling for credential retrieval failures
  • Type Safety: Full TypeScript support with intelligent code completion and compile-time validation
  • Production Ready: Battle-tested utility used in real Adobe Commerce extensions

useRouteParams

A React hook that provides a clean API for accessing React Router parameters and navigation functions.

import { useRouteParams } from '@adobe-commerce/aio-experience-kit';

const ProductDetail = () => {
  const { getParam, getNavigate } = useRouteParams();
  
  const productId = getParam('id');
  const navigate = getNavigate();
  
  const handleBack = () => {
    navigate('/products');
  };
  
  return (
    <div>
      <h1>Product {productId}</h1>
      <button onClick={handleBack}>Back to Products</button>
    </div>
  );
};

Features:

  • Parameter Access: Type-safe access to URL parameters with automatic type inference and null safety
  • Navigation Control: Wrapped navigation function with programmatic routing and history management
  • Clean API: Simplified interface that abstracts React Router complexity while maintaining full functionality
  • Hook Integration: Seamless integration with React component lifecycle and state management patterns
  • Error Handling: Built-in protection against navigation errors and invalid route parameters
  • Performance Optimized: Efficient parameter extraction and navigation with minimal re-renders

TypeScript Support

This library is built with TypeScript and provides comprehensive type definitions for all components and utilities. Import types as needed:

import type {
  MainContainerProps,
  DataTableProps,
  DataFormProps,
  ConfirmationDialogProps,
  FileUploadProps,
  FileUploadHandle,
  FieldType,
  AdminUiSdkInterface,
  AdminUiSdkCredentials
} from '@adobe-commerce/aio-experience-kit';

// Deprecated types (for backward compatibility only)
// These types are deprecated and will be removed in v2.0.0
// import type { 
//   ShippingCarrierFormProps, 
//   SelectOption,
//   AdminUiSdkRegistration,
//   MenuItem
// } from '@adobe-commerce/aio-experience-kit';

License

See the LICENSE file (in package) for license rights and limitations.