Core UXP Components

Build powerful data-driven views using UXP's core components. This guide walks you through building a complete view from scratch.


Overview

UXP provides a rich set of components for building data-driven applications:

  • ObjectSearchComponent - Advanced data table with search, filters, views, and actions

  • ObjectDetailsPanel - Collapsible side panel for viewing object details

  • SlideInForm - Slide-in panel for creating/editing objects

  • DataEntryForm - Simple form with validation

  • DynamicForm - Dynamic form builder from configuration

  • ActionsListComponent - Action buttons with dropdown support

  • ButtonGroup - Grouped action buttons

We'll build a Location Management view progressively, starting simple and adding features step by step.


Step 1: Simple List

Let's start with a basic list view using ObjectSearchComponent:

// src/views/portfolio/PortfolioView.tsx
import {
    ObjectSearchComponent,
    useExecuteRequestCallback,
    type OSCColumn,
    type RowData,
    type Filters,
    type Sort
} from "uxp/components";
import { LocationServices } from "../../services";

const PortfolioView = () => {
    const executeGetAll = useExecuteRequestCallback(
        LocationServices.getAll()
    );

    const getAll = async (
        page: number,
        pageSize: number,
        query?: string,
        filters?: Filters,
        sort?: Sort
    ): Promise<{ items: RowData[] }> => {
        const params = { page, pageSize, q: query };
        const { data } = await executeGetAll(params);
        return { items: data || [] };
    };

    const columns: OSCColumn[] = [
        {
            id: 'Name',
            label: 'Name',
            isSortable: true
        },
        {
            id: 'LocationType',
            label: 'Type',
            isSortable: true
        },
        {
            id: 'Status',
            label: 'Status'
        }
    ];

    return (
        <ObjectSearchComponent
            data={getAll}
            idField="Key"
            columns={columns}
            pageSize={50}
        />
    );
};

export default PortfolioView;

Key Points:

  • useExecuteRequestCallback creates a callback for API requests

  • getAll function signature: (page, pageSize, query?, filters?, sort?) => Promise<{ items: RowData[] }>

  • columns uses OSCColumn[] type for table structure

  • idField specifies unique identifier field

  • Component handles pagination, search, and sorting automatically


Step 2: Add Filters

Add filters to let users narrow down results:

Filter Configuration:

  • FilterConfig structure: { formFields: FormSectionProps[] }

  • Each section has: title, columns, fields: DynamicFormFieldProps[]

  • Field types: 'select', 'text', 'date', 'checkbox', 'number', etc.

  • Filter values are passed to getAll via filters parameter

  • ⚠️ Access filter values via filters.filters.fieldName (note the double .filters)

Important Notes:

  • ⚠️ total prop is required on ObjectSearchComponent (can be 0 if unknown)

  • ⚠️ Filter structure is filters.filters.fieldName NOT filters.fieldName

  • ⚠️ Use hasValue() to check if filter value exists before adding to params

  • ⚠️ Always verify exact prop names in Resources/views/uxp.d.ts


Step 3: Add Views

Views let users switch between different filtered sets (e.g., "All", "Active", "Archived"):

Views Configuration:

  • Each view uses View interface with id, name, and configurations

  • configurations.filters contains the filter values

  • defaultviewId sets which view loads initially

  • allowToMangeCustomViews enables user-created custom views

  • Switching views applies the view's filter automatically

  • Users can still add additional filters on top of view filters


Step 4: Add Details Panel

Show detailed information about a selected item using ObjectDetailsPanel:

Creating a Details Panel Component:

Details Panel Features:

  • CustomDetailsPanelProps provides renderDetails function

  • renderDetails receives itemId (from row's idField) and onClose callback

  • collapsed prop controls initial state

  • Panel opens when user clicks a row

  • Uses URL params to track selection

  • Define proper interfaces for your data types (LocationData)


Step 5: Add Forms (Create/Edit)

Add forms for creating and editing objects using SlideInForm:

5.1: Using SlideInForm with DynamicForm

5.2: Creating the Form Component

Form Features:

  • FormSectionProps[]: Organize form into sections

  • DynamicFormFieldProps: Each field with proper type definitions

  • Conditional visibility: show property based on form data

  • Paginated options: getPaginatedOptions for large datasets

  • Custom label resolvers: selectedOptionLabel for async selects

  • Validation: Built-in validation with validate property

  • Type safety: All interfaces properly defined


Step 6: Add Actions (Edit, Delete)

Add action buttons to each row using useDeleteAction:

Action Features:

  • useDeleteAction(): Returns object with delete() method

  • DeleteActionParams: Interface for delete configuration

    • model: Model name in format "App.Model"

    • key: Primary key of object to delete

    • canHide: Allow hiding if delete fails due to dependencies

    • onSuccess: Callback with action type ('delete' | 'hide')

    • onError: Error callback

  • Custom Actions: Render actions in columns with renderColumn

  • Refresh pattern: Use key prop with state to force re-render


Core Hooks Reference

useSearchParams

Manage URL search parameters for state persistence:

Signature:

Example:

Note: Returns the search params object directly. To modify params, use useRouterContext().navigate() or generateURL().

useRouterContext

Access navigation utilities and router state:

Signature:

Example:

useDeleteAction

Pre-built hook for delete/restore operations with dependency checking:

Signature:

Example:

useExecuteRequest

Execute API request with automatic loading state, debounce, and polling:

Signature:

Example:

useExecuteRequestCallback

Create a stable callback for API requests (no state updates):

Signature:

Example:

usePluggableView

Make your view customizable/replaceable by other apps:

Signature:

Example:

useMultiEventSubscriber

Subscribe to multiple real-time events:

Signature:

Example:


Component API Reference

For detailed API documentation, see the generated docs:

Core Components

Action Components

Layout Components

Form Components


Complete Example

Here's the full PortfolioView with all features and proper TypeScript types:

Key Type Features in Complete Example:

  • All interfaces properly defined (SearchParams, LocationData)

  • Type imports using type keyword

  • Proper generic usage: useExecuteRequest<string[]>, useSearchParams<SearchParams>

  • All callbacks properly typed with parameter and return types

  • OSCColumn[] for columns

  • DynamicFormFieldProps[] for filter fields

  • View[] and ViewsConfig for views configuration

  • DeleteActionParams for delete operations

  • GenerateURLOptions for URL generation

  • No any types - everything explicitly typed


Next Steps

Now that you understand core components, continue to:

Last updated