***

title: 'Action Bar Items'
metaTitle: 'Adding Action Bar Buttons to Vendure Dashboard Pages'
metaDescription: 'Add custom buttons and dropdown menu items to the action bar of any Vendure Dashboard page, with context access, loading states, and permission guards.'
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The Action Bar is the bar at the top of the page where you can add
buttons and other actions.

:::info
All available options are documented in the [DashboardActionBarItem reference](/current/core/reference/dashboard/extensions-api/action-bar#dashboardactionbaritem)
:::

## Basic Action Bar Item

Here's a simple example of adding a button to the action bar:

```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
import { Button, defineDashboardExtension } from '@vendure/dashboard';
import { useState } from 'react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-detail',
            component: ({ context }) => {
                const [count, setCount] = useState(0);
                return (
                    <Button type="button" variant="secondary" onClick={() => setCount(x => x + 1)}>
                        Counter: {count}
                    </Button>
                );
            },
        },
    ],
});
```

![Action bar button](action-bar-button.webp)

## Location and position

The `pageId` property is required in order to specify on which page the action bar item should appear.
By default, the item will be placed to the left of any existing action bar items.

However, since Vendure v3.6.0, you can also specify the `position` property for more control over the placement of your action bar item.

See the section on [finding page and item ids](#finding-page-ids) below for help in determining the correct `pageId` and `itemId` values.

```typescript
import { Button, defineDashboardExtension } from '@vendure/dashboard';
import { useState } from 'react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-detail',
            component: ({ context }) => {
                // omitted for brevity
            },
            // highlight-start
            position: {
                // The ID of the existing action bar item to position relative to
                itemId: 'save-button',
                // Order can be 'before', 'after' or 'replace'
                order: 'after',
            },
            // highlight-end
        },
    ],
});
```

## Context Data

The `context` prop provides access to:

* **`entity`**: The current entity being viewed/edited (e.g., Product, Customer, etc.)
* **`form`**: The React Hook Form instance for the current page (if applicable)
* **`route`**: Route information and parameters

## Dropdown Menu

You can also define dropdown menu items for the Action Bar. This is useful for secondary actions that are needed
less often by administrators.

Make sure to always wrap these in the `DropdownMenuItem` component for consistent styling.

```tsx
import { DropdownMenuItem, defineDashboardExtension } from '@vendure/dashboard';
import { useState } from 'react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-list',
            type: 'dropdown',
            component: () => <DropdownMenuItem variant="default">My Item</DropdownMenuItem>,
        },
    ],
});
```

![Action bar dropdown](action-bar-dropdown.webp)

## Practical Examples

### Export Button

```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
import { Button, defineDashboardExtension } from '@vendure/dashboard';
import { DownloadIcon } from 'lucide-react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-detail',
            component: ({ context }) => {
                const product = context.entity;

                const handleExport = async () => {
                    // Export product data
                    const data = JSON.stringify(product, null, 2);
                    const blob = new Blob([data], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);

                    const a = document.createElement('a');
                    a.href = url;
                    a.download = `product-${product.id}.json`;
                    a.click();

                    URL.revokeObjectURL(url);
                };

                return (
                    <Button variant="outline" onClick={handleExport} disabled={!product}>
                        <DownloadIcon className="mr-2 h-4 w-4" />
                        Export
                    </Button>
                );
            },
        },
    ],
});
```

### Sync Button with Loading State

```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
import { Button, defineDashboardExtension, toast } from '@vendure/dashboard';
import { RefreshCwIcon } from 'lucide-react';
import { useState } from 'react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-detail',
            component: ({ context }) => {
                const [isSyncing, setIsSyncing] = useState(false);
                const product = context.entity;

                const handleSync = async () => {
                    if (!product) return;

                    setIsSyncing(true);
                    try {
                        // Simulate API call to external system
                        await fetch(`/api/sync-product/${product.id}`, {
                            method: 'POST',
                        });
                        toast.success('Product synced successfully');
                    } catch (error) {
                        toast.error('Failed to sync product');
                    } finally {
                        setIsSyncing(false);
                    }
                };

                return (
                    <Button variant="outline" onClick={handleSync} disabled={!product || isSyncing}>
                        <RefreshCwIcon className={`mr-2 h-4 w-4 ${isSyncing ? 'animate-spin' : ''}`} />
                        {isSyncing ? 'Syncing...' : 'Sync to ERP'}
                    </Button>
                );
            },
        },
    ],
});
```

### Conditional Action Bar Items

You can conditionally show action bar items based on the entity or user permissions:

```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
import { Button, defineDashboardExtension, PermissionGuard } from '@vendure/dashboard';
import { SendIcon } from 'lucide-react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'customer-detail',
            component: ({ context }) => {
                const customer = context.entity;

                // Only show for customers with email addresses
                if (!customer?.emailAddress) {
                    return null;
                }

                const handleSendEmail = () => {
                    // Open email composer or trigger email send
                    console.log('Sending email to:', customer.emailAddress);
                };

                return (
                    <PermissionGuard requires={['UpdateCustomer']}>
                        <Button variant="outline" onClick={handleSendEmail}>
                            <SendIcon className="mr-2 h-4 w-4" />
                            Send Email
                        </Button>
                    </PermissionGuard>
                );
            },
        },
    ],
});
```

## Multiple Action Bar Items

You can add multiple action bar items to the same page:

```tsx title="src/plugins/my-plugin/dashboard/index.tsx"
import { Button, defineDashboardExtension } from '@vendure/dashboard';
import { DownloadIcon, RefreshCwIcon, SendIcon } from 'lucide-react';

defineDashboardExtension({
    actionBarItems: [
        {
            pageId: 'product-detail',
            component: ({ context }) => (
                <Button variant="outline">
                    <DownloadIcon className="mr-2 h-4 w-4" />
                    Export
                </Button>
            ),
        },
        {
            pageId: 'product-detail',
            component: ({ context }) => (
                <Button variant="outline">
                    <RefreshCwIcon className="mr-2 h-4 w-4" />
                    Sync
                </Button>
            ),
        },
        {
            pageId: 'product-detail',
            component: ({ context }) => (
                <Button variant="outline">
                    <SendIcon className="mr-2 h-4 w-4" />
                    Share
                </Button>
            ),
        },
    ],
});
```

## Available Button Variants

The dashboard provides several button variants you can use:

* `default` - Primary button style
* `secondary` - Secondary button style
* `outline` - Outlined button style
* `ghost` - Minimal button style
* `destructive` - For destructive actions (delete, etc.)

```tsx
<Button variant="default">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete</Button>
```

## Best Practices

1. **Use appropriate icons**: Icons help users quickly understand the action
2. **Provide loading states**: Show loading indicators for async operations
3. **Handle errors gracefully**: Use toast notifications for feedback
4. **Consider permissions**: Use `PermissionGuard` for actions that require specific permissions
5. **Keep labels concise**: Use short, descriptive labels for buttons
6. **Group related actions**: Consider the order and grouping of multiple action items
7. **Test thoroughly**: Verify your actions work correctly across different entity states

## Finding Page and Item IDs

To find the `pageId` and `itemId` for your action bar items:

1. Enable [Dev Mode](/current/core/extending-the-dashboard/extending-overview/#dev-mode) in the dashboard
2. Navigate to the page where you want to add your action
3. Hover the page or existing action bar item to reveal its IDs
4. Use these IDs in your action bar item configuration

The [Extension Targets reference](/current/core/extending-the-dashboard/customizing-pages/extension-targets/) lists the most common built-in page IDs, block IDs, action bar item IDs, and toolbar item IDs.
