Skip to content

API Reference

Complete reference for all public exports from @middag-io/react.

Import path

All exports are available from the package root: import { ... } from '@middag-io/react'. Types are exported with the type keyword.

Components

ContractPage

Main page renderer. Resolves shell, layout, and blocks from registries based on the PageContract. This is the only component most consumers need.

tsx
<ContractPage contract={contract} overlay? help? inspector? />
PropTypeRequiredDefaultDescription
contractPageContractYesThe page contract describing shell, layout, and blocks to render.
overlaybooleanNofalseWhen true, renders the page in a full-screen overlay with a close button.
helpHelpDataNoContextual help content shown in the ContextAside panel.
inspectorInspectorDataNoInspector side-panel configuration (endpoint URL and width).

Registration Functions

Functions for populating the shell, layout, and block registries. Call registerDefaults() once at app startup to register all built-in components.

registerDefaults()

ts
function registerDefaults(): void

Registers all built-in shells (product, admin), layouts (stack, split, dashboard, master-detail, wizard, canvas), and all 16 block types. Idempotent -- safe to call multiple times.

registerShell(key, component)

ts
function registerShell(key: Shell, component: ComponentType<ShellProps>): void

Register a custom shell component for a given shell key. Overrides the default if the key already exists.

ArgumentTypeDescription
key'product' | 'admin' | 'course' | 'immersive'Shell identifier matching the contract shell field.
componentComponentType<ShellProps>React component that receives { children } and renders the shell chrome.

registerLayout(key, component)

ts
function registerLayout(key: string, component: ComponentType<LayoutProps>): void

Register a custom layout component for a given template key.

ArgumentTypeDescription
keystringLayout template key (e.g. 'stack', 'split', 'dashboard').
componentComponentType<LayoutProps>React component receiving { layout, renderBlock }.

registerBlock(key, component)

ts
function registerBlock<TData>(key: string, component: ComponentType<BlockProps<TData>>): void

Register a custom block component for a given block type key.

ArgumentTypeDescription
keystringBlock type key (e.g. 'dense_table', 'metric_card').
componentComponentType<BlockProps<TData>>React component receiving { block } with typed data.

Registries

The three registries are Map instances that store the mapping from contract keys to React components. Populated by registerDefaults() or individual register* calls.

RegistryTypeBuilt-in entries
shellRegistryMap<Shell, ComponentType<ShellProps>>product, admin
layoutRegistryMap<string, ComponentType<LayoutProps>>stack, split, dashboard, master-detail, wizard, canvas
blockRegistryMap<string, ComponentType<BlockProps>>16 block types

Providers

I18nProvider

tsx
<I18nProvider asyncResolver?={resolver}>{children}</I18nProvider>

Translation provider. Reads pre-loaded strings from Inertia shared props (theme.strings). Optionally accepts an async resolver for keys not pre-loaded by the server.

PropTypeRequiredDescription
childrenReactNodeYesChild components that can access translation functions.
asyncResolverAsyncStringResolverNoOptional async function to resolve translation keys not in the pre-loaded strings.

See Providers Guide and i18n Guide for details.

useTranslation()

ts
function useTranslation(): { t, tAsync }
ReturnTypeDescription
t(key: string) => stringSynchronous lookup. Returns the key itself if not yet loaded.
tAsync(key: string, component?: string) => Promise<string>Async lookup using the injected resolver. Falls back to returning the key.

Theme Functions

Appearance management with host detection and manual override. Three-tier resolution: manual > host (Moodle/WP) > OS.

FunctionSignatureDescription
getStoredAppearance() => AppearanceRead stored preference from localStorage. Returns 'system' if none.
setAppearance(pref: Appearance) => voidPersist preference, resolve effective theme, apply to DOM.
cycleAppearance() => AppearanceCycle: system > light > dark > system. Persists and applies.
getEffectiveTheme(pref: Appearance) => 'light' | 'dark'Resolve 'system' to concrete theme via host detection + OS.
applyTheme(theme: EffectiveTheme) => voidApply resolved theme to DOM (data-theme on .middag-root, class on html).
toggleDir() => 'ltr' | 'rtl'Toggle document direction. Persists in localStorage.
initDir() => voidRestore persisted direction on page load.
onSystemThemeChange(cb?: () => void) => () => voidListen for OS theme changes. Only reacts when preference is 'system'. Returns cleanup function.

See Theme Guide for usage examples.

Hooks

useIsDark()

ts
function useIsDark(): boolean

Returns true when the effective theme is 'dark'. Reacts to theme changes via the data-theme attribute on .middag-root elements.

tsx
import { useIsDark } from '@middag-io/react';

function Logo() {
    const isDark = useIsDark();
    return <img src={isDark ? '/logo-white.svg' : '/logo-dark.svg'} alt="Logo" />;
}

Types: Page Contract

Core types for the contract-driven page system. The backend sends PageContract via Inertia props.

ts
interface PageContract {
    version: '1';
    shell: 'product' | 'admin' | 'course' | 'immersive';
    page: PageMeta;
    layout: LayoutDescriptor;
    resources?: PageResources;
}

interface PageMeta {
    key: string;
    title: string;
    subtitle?: string;
    icon?: string;
    badge?: PageBadge;
    favoritable?: boolean;
    breadcrumbs?: Breadcrumb[];
    actions?: PageAction[];
    filterTabs?: PageFilterTab[];
    activeFilterTab?: string;
}

interface BlockDescriptor<TData = Record<string, unknown>> {
    type: string;       // block type key (e.g. 'dense_table')
    key: string;        // unique key within the page
    data: TData;        // typed data payload
    variant?: string;
    title?: string;
    subtitle?: string;
    actions?: PageAction[];
    meta?: Record<string, unknown>;
}

interface LayoutDescriptor {
    template: 'stack' | 'split' | 'dashboard' | 'master-detail' | 'wizard' | 'canvas';
    regions: Record<string, BlockDescriptor[]>;
    meta?: Record<string, unknown>;
}

interface HelpData {
    title: string;
    description: string;
    sections?: HelpSection[];
    tips?: HelpTip[];
    shortcuts?: HelpShortcut[];
    learnMore?: string;
}

interface ContractPageProps {
    contract: PageContract;
    overlay?: boolean;
    help?: HelpData;
    inspector?: InspectorData;
}

Types: SharedProps

Typed Inertia shared props sent on every request.

ts
interface SharedProps {
    navigation: NavigationPayload | NavigationTreePayload;
    auth: SharedPropsAuth;
    theme: SharedPropsTheme;
    flash?: SharedPropsFlash;
    locale: string;       // e.g. 'pt-BR', 'en'
    version: string;      // e.g. '5.0.0'
    scope?: Record<string, unknown>;
    [key: string]: unknown;
}

interface SharedPropsAuth {
    id: number;
    name: string;
    email: string;
    avatarUrl?: string;
    capabilities: string[];
}

interface SharedPropsTheme {
    strings?: Record<string, string>;
    appearance?: 'system' | 'light' | 'dark';
    brandColor?: string;
    inherit?: boolean;
}

Types: Navigation

Navigation contract types. Two shapes are supported: legacy sections-based and the newer unified tree model.

ts
interface NavigationPayload {
    sections: NavigationSection[];
    activeKey: string;
}

interface NavigationTreePayload {
    tree: NavigationNode[];
    activeKey: string;
    drilldownStack?: string[];
    footer: NavigationNode[];
}

interface NavigationNode {
    key: string;
    label: string;
    icon?: string;
    entityType?: NavigationEntityType;
    href?: string;
    badge?: string | number;
    badgeVariant?: 'count' | 'alert';
    active?: boolean;
    drilldown?: boolean;
    collapsible?: boolean;
    defaultOpen?: boolean;
    statusColor?: string;
    children?: NavigationNode[];
}

See Navigation Guide for usage details.

Types: Registry

Props interfaces for registered components.

ts
// Shell component receives children to render inside the chrome
type ShellProps = { children: ReactNode };

// Layout component receives the layout descriptor and a render function
type LayoutProps = {
    layout: LayoutDescriptor;
    renderBlock: (block: BlockDescriptor) => ReactElement | null;
};

// Block component receives the full block descriptor with typed data
type BlockProps<TData = Record<string, unknown>> = {
    block: BlockDescriptor<TData>;
};

Types: Block Data

Data contracts for all 16 registered block types. Each block component receives a BlockDescriptor<TData> where TData is one of these interfaces.

Type KeyData InterfaceDescription
dense_tableDenseTableBlockDataFull-featured table with sort, filter, pagination, bulk/row actions, density toggle.
metric_cardMetricCardBlockDataKPI card with value, delta, icon, optional link.
status_stripStatusStripBlockDataHorizontal health indicators with score dots and key/value pairs.
detail_panelDetailPanelBlockDataSections of label/value fields (text, status, timestamp, link, code, email).
activity_timelineActivityTimelineBlockDataGrouped timeline entries with actor, action, icon, color, timestamp.
card_gridCardGridBlockDataCard-based grid. Variants: default, store, connector.
markdown_panelMarkdownPanelBlockDataSanitized markdown rendering with syntax highlight and copy button.
link_listLinkListBlockDataVertical list of links with icon, label, description.
tabbed_panelTabbedPanelBlockDataTab container that nests other blocks. Each tab has key, label, and blocks array.
empty_stateEmptyStateBlockDataEmpty/error/first-use placeholder. Variants: first-use, no-results, error, permission.
form_panelFormPanelBlockDataSchema-driven form with sections, groups, conditional fields, dirty tracking.
action_gridActionGridBlockDataGrid of action cards with icon, title, description, execute button.
condition_treeConditionTreeBlockDataAND/OR tree for condition rules with nesting.
sentence_builderSentenceBuilderBlockDataNatural language rule builder for audience segments.
flow_editorFlowEditorBlockDataCanvas with draggable nodes and edges for workflow editing.
form_builderFormBuilderBlockDataDrag-and-drop form field builder.

See Block Catalog for data shape examples.

Types: Theme

ts
type Appearance = 'system' | 'light' | 'dark';
type EffectiveTheme = 'light' | 'dark';
type AsyncStringResolver = (key: string, component?: string) => Promise<string>;

Other Page Types

ts
type Shell = 'product' | 'admin' | 'course' | 'immersive';

type LayoutTemplate = 'stack' | 'split' | 'dashboard'
    | 'master-detail' | 'wizard' | 'canvas';

interface PageFilterTab {
    key: string; label: string; badge?: number | string;
}

interface Breadcrumb {
    label: string; href?: string; external?: boolean;
}

interface PageAction {
    id: string; label: string; intent: ActionIntent;
    href?: string; method?: ActionMethod; icon?: string;
    requiresConfirmation?: boolean; disabled?: boolean;
}

interface InspectorData { endpoint: string; width: number; }

interface HelpSection { title: string; body: string; }

interface HelpTip { icon?: string; text: string; }

interface HelpShortcut { keys: string; action: string; }

Released under the proprietary license.