Back to Vendure

Public API & Imports

docs/docs/guides/extending-the-dashboard/public-api/index.mdx

3.7.110.9 KB
Original Source

When building dashboard extensions, everything you need should be imported from @vendure/dashboard. This is the single most important convention to follow, and this page explains exactly what that means, why it matters, and the few exceptions to the rule.

Why a Single Import Source?

The Vendure Dashboard is built on top of several third-party libraries — Base UI, TanStack Router, TanStack Query, React Hook Form, and others. Over time, these libraries may be replaced, upgraded, or wrapped with custom behavior.

To protect your extensions from breaking when that happens, the @vendure/dashboard package re-exports everything you need from these libraries. As long as you import from @vendure/dashboard, your code is insulated from changes to the underlying implementation.

Here is a real-world example: the Dashboard originally used Radix UI primitives for its component library. In a later release, the underlying primitives were migrated to Base UI. Extensions that imported components from @vendure/dashboard continued to work without any changes. Extensions that had imported directly from @radix-ui/* packages broke.

:::caution[The Golden Rule] Always import from @vendure/dashboard first. If it is exported from this package, that is where you get it. Do not import the same thing directly from a third-party package. :::

What is Available from @vendure/dashboard?

The public API covers everything you should need to build dashboard extensions. The sections below highlight the most commonly used exports — for the full set, use your IDE's autocomplete on @vendure/dashboard imports.

UI Components

All design-system components (buttons, inputs, dialogs, cards, selectors, etc.) are available directly:

tsx
import { Button, Card, Input, Dialog, Select, Badge, Tabs } from '@vendure/dashboard';

These are the same components used internally by the Dashboard itself, styled with the Vendure design tokens.

Data Display & Input Components

Vendure-specific components for displaying and editing data:

tsx
import {
    // Display
    Money, DateTime, Boolean, Json,
    // Input
    TextInput, MoneyInput, RichTextInput, DatetimeInput,
    BooleanInput, SelectWithOptions, RelationInput,
} from '@vendure/dashboard';

Data Tables

Everything for building list views with sortable, filterable tables:

tsx
import { DataTable, DataTableColumnHeader, DataTablePagination } from '@vendure/dashboard';

Page Layout & Navigation

tsx
import {
    Page, PageTitle, PageLayout, PageBlock,
    DetailPage, ListPage, Link,
} from '@vendure/dashboard';

Framework & Extension API

The core APIs for defining extensions, registering custom components, and integrating with the Dashboard framework:

tsx
import {
    defineDashboardExtension,
    useDetailPage, useExtendedDetailQuery, useExtendedListQuery,
    detailPageRouteLoader,
} from '@vendure/dashboard';

Hooks

All custom hooks for accessing Dashboard state and services:

tsx
import {
    useAuth, useChannel, usePermissions, useServerConfig,
    useLocalFormat, useTheme, useAlerts, usePage, usePageBlock,
} from '@vendure/dashboard';

GraphQL Utilities

The api helper and gql.tada type utilities are available from @vendure/dashboard:

tsx
import { api, ResultOf, FragmentOf, VariablesOf, readFragment } from '@vendure/dashboard';

:::note The graphql tagged template function is not something you should import from @vendure/dashboard. See the @/gql exception below for why. :::

TanStack Query (Data Fetching)

Re-exported from @tanstack/react-query:

tsx
import {
    useQuery, useMutation, useQueryClient,
    useInfiniteQuery, useSuspenseQuery,
    queryOptions, keepPreviousData,
} from '@vendure/dashboard';
import type { UseQueryOptions, UseMutationOptions, QueryClient } from '@vendure/dashboard';

TanStack Router (Routing)

Re-exported from @tanstack/react-router:

tsx
import {
    Link, Outlet, useRouter, useNavigate,
    useRouterState, useBlocker,
} from '@vendure/dashboard';
import type { AnyRoute, LinkProps, RouteOptions } from '@vendure/dashboard';

The AnyRoute type is commonly needed when typing custom route definitions.

TanStack Table (Table Types)

Re-exported from @tanstack/react-table:

tsx
import type {
    ColumnDef, Column, Row, CellContext, HeaderContext,
    SortingState, ColumnFiltersState, VisibilityState,
    TableInstance, AccessorFnColumnDef, ColumnSort,
    ExpandedState, RowSelectionState,
} from '@vendure/dashboard';

:::note The TanStack Table Table type is re-exported as TableInstance to avoid a naming conflict with the Dashboard's own Table UI component. If you are following TanStack Table documentation, replace Table with TableInstance in your imports. :::

React Hook Form

Re-exported from react-hook-form:

tsx
import {
    useForm, useFormContext, useFieldArray, useWatch,
    Controller, FormProvider,
} from '@vendure/dashboard';
import type { Control, UseFormReturn, FieldValues, FieldPath } from '@vendure/dashboard';

Zod (Schema Validation)

Re-exported from zod. Used for form validation with zodResolver:

tsx
import { z, zodResolver } from '@vendure/dashboard';
import type { ZodType, ZodObject, ZodArray, ZodEffects } from '@vendure/dashboard';

The dashboard accepts both Zod v3 and v4 (^3.25.0 || ^4.0.0). If your extension already imports z from zod directly, it will continue to work — zodResolver handles both versions at runtime. However, importing from @vendure/dashboard is recommended to stay insulated from future changes.

Toast Notifications

Re-exported from sonner:

tsx
import { toast } from '@vendure/dashboard';

Animations

Re-exported from motion/react:

tsx
import {
    motion, AnimatePresence, LayoutGroup,
    useSpring, useTransform, useMotionValue,
    useAnimation, useInView,
} from '@vendure/dashboard';
import type { Variants, Transition, MotionProps } from '@vendure/dashboard';

Utility Functions

tsx
import {
    cn, camelCaseToTitleCase, formatFileSize, normalizeString,
    removeReadonlyAndLocalizedCustomFields,
} from '@vendure/dashboard';

The removeReadonlyAndLocalizedCustomFields helper is particularly useful when building custom forms that work with custom fields — it strips read-only and localized fields before mutation submission.

Constants

tsx
import {
    NEW_ENTITY_PATH, AUTHENTICATED_ROUTE_PREFIX,
    DEFAULT_CHANNEL_CODE, SUPER_ADMIN_ROLE_CODE, CUSTOMER_ROLE_CODE,
} from '@vendure/dashboard';

Exceptions — What to Import Directly

A small number of packages should be imported from their own modules because they are either not re-exported, or re-exporting them is not practical:

react

React itself is a peer dependency. Import hooks and utilities directly:

tsx
import { useState, useEffect, useCallback, useMemo } from 'react';

lucide-react

Icons are imported directly from lucide-react. There are thousands of icons and re-exporting them all would be impractical. The LucideIcon type is available from @vendure/dashboard if you need it for typing.

tsx
import { ShoppingCartIcon, UserIcon, SettingsIcon } from 'lucide-react';
import type { LucideIcon } from '@vendure/dashboard'; // for typing icon props

@lingui/react/macro

The Lingui i18n macros (Trans, useLingui from the macro entry point) must be imported from their macro module because they are compile-time transforms:

tsx
import { Trans, useLingui } from '@lingui/react/macro';

:::note The non-macro useLingui hook is re-exported from @vendure/dashboard, but the macro version from @lingui/react/macro is what you should use in practice since it provides the t tagged template function. :::

@/gql

The graphql tagged template function must be imported from the @/gql path alias — not from @vendure/dashboard:

tsx
import { graphql } from '@/gql';

This is because gql.tada needs to be initialized against your project's GraphQL schema, which includes any custom fields, custom types, or API extensions defined by your plugins. The @/gql path points to the types that the Vendure Vite plugin generates from your specific schema during development.

If you were to import graphql from @vendure/dashboard, it would be initialized against the base Vendure schema only — your queries would compile, but the types would not reflect your custom schema extensions, leading to silent type errors.

All other GraphQL utilities (api, ResultOf, FragmentOf, VariablesOf, readFragment) are correctly imported from @vendure/dashboard.

Quick Reference

What you needImport from
UI components (Button, Dialog, Card, ...)@vendure/dashboard
Data components (TextInput, MoneyInput, ...)@vendure/dashboard
Hooks (useAuth, useChannel, useLocalFormat, ...)@vendure/dashboard
Extension API (defineDashboardExtension, ...)@vendure/dashboard
GraphQL utilities (api, ResultOf, FragmentOf, ...)@vendure/dashboard
TanStack Query (useQuery, useMutation, ...)@vendure/dashboard
TanStack Router (Link, useNavigate, AnyRoute, ...)@vendure/dashboard
TanStack Table types (ColumnDef, TableInstance, ...)@vendure/dashboard
React Hook Form (useForm, Controller, ...)@vendure/dashboard
Zod (z, zodResolver, ZodType, ...)@vendure/dashboard
Toast (toast)@vendure/dashboard
Animations (motion, AnimatePresence, ...)@vendure/dashboard
Utility functions (cn, ...)@vendure/dashboard
Constants@vendure/dashboard
React hooks (useState, useEffect, ...)react
Icons (ShoppingCartIcon, ...)lucide-react
i18n macros (Trans, useLingui)@lingui/react/macro
graphql tagged template function@/gql

Common Mistakes

Importing UI components from the underlying library

tsx
// Wrong — imports directly from the underlying component library
import { Button } from '@base-ui/react';
import { Dialog } from '@radix-ui/react-dialog';

// Correct
import { Button, Dialog } from '@vendure/dashboard';

Importing TanStack hooks directly

tsx
// Wrong — bypasses the dashboard re-export
import { useQuery } from '@tanstack/react-query';
import { useNavigate } from '@tanstack/react-router';

// Correct
import { useQuery, useNavigate } from '@vendure/dashboard';

Importing React Hook Form directly

tsx
// Wrong
import { useForm } from 'react-hook-form';

// Correct
import { useForm } from '@vendure/dashboard';

Importing Zod or zodResolver directly

tsx
// Wrong — bypasses the dashboard re-export
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

// Correct
import { z, zodResolver } from '@vendure/dashboard';

Following these conventions keeps your extensions stable across Dashboard upgrades and ensures you always get the correctly configured versions of these utilities.