Skip to main content
Dynamic UI uses React Context to provide global configuration for theming, internationalization, and portal management.

DContext

The main context provider that supplies global configuration including currency settings, icons, breakpoints, and language preferences.

Import

import { DContextProvider, useDContext } from '@dynamic-framework/ui-react';

Provider Props

type DContextProviderProps<T extends Record<string, unknown>> = {
  language?: string;
  currency?: CurrencyProps;
  icon?: IconProps;
  iconMap?: IconMapProps;
  portalName?: string;
  availablePortals?: PortalAvailableList<T>;
  children: ReactNode;
}
language
string
default:"en"
The current language code for internationalization
currency
CurrencyProps
Currency formatting configuration
type CurrencyProps = {
  symbol: string;      // Currency symbol (e.g., "$", "€")
  precision: number;   // Decimal places
  separator: string;   // Thousands separator
  decimal: string;     // Decimal separator
}
Default:
{
  "symbol": "$",
  "precision": 2,
  "separator": ",",
  "decimal": "."
}
icon
IconProps
Icon library configuration
type IconProps = {
  familyClass: string;    // CSS class for icon family
  familyPrefix: string;   // Prefix for icon names
  materialStyle: boolean; // Use material design style
}
Default:
{
  "familyClass": "bi",
  "familyPrefix": "bi-",
  "materialStyle": false
}
iconMap
IconMapProps
Mapping of semantic icon names to actual icon identifiers
type IconMapProps = {
  x: string;
  xLg: string;
  chevronDown: string;
  chevronUp: string;
  chevronLeft: string;
  chevronRight: string;
  alert: AlertThemeIconMap;
  upload: string;
  calendar: string;
  check: string;
  input: {
    search: string;
    show: string;
    hide: string;
    decrease: string;
    increase: string;
  };
}
portalName
string
default:"d-portal"
ID for the portal container element
availablePortals
PortalAvailableList<T>
Map of portal components for modal/overlay management. See DPortalContext for details.

Context Value

type DContextValue<T extends Record<string, unknown>> = {
  language: string;
  currency: CurrencyProps;
  icon: IconProps;
  iconMap: IconMapProps;
  breakpoints: BreakpointProps;
  setContext: (value: Partial<DContextValue<T>>) => void;
}
language
string
Current language code
currency
CurrencyProps
Current currency settings
icon
IconProps
Current icon library configuration
iconMap
IconMapProps
Current icon mappings
breakpoints
BreakpointProps
Current breakpoint values (automatically read from CSS custom properties)
type BreakpointProps = {
  xs: string;   // e.g., "0px"
  sm: string;   // e.g., "576px"
  md: string;   // e.g., "768px"
  lg: string;   // e.g., "992px"
  xl: string;   // e.g., "1200px"
  xxl: string;  // e.g., "1400px"
}
setContext
function
Function to update context values dynamically
(value: Partial<DContextValue<T>>) => void

Usage

Basic Setup

import { DContextProvider } from '@dynamic-framework/ui-react';

function App() {
  return (
    <DContextProvider>
      <YourApp />
    </DContextProvider>
  );
}

Custom Currency

import { DContextProvider } from '@dynamic-framework/ui-react';

function App() {
  return (
    <DContextProvider
      currency={{
        symbol: '€',
        precision: 2,
        separator: '.',
        decimal: ','
      }}
      language="de"
    >
      <YourApp />
    </DContextProvider>
  );
}

Accessing Context

import { useDContext } from '@dynamic-framework/ui-react';

function CurrencyDisplay() {
  const { currency, language } = useDContext();

  return (
    <div>
      Language: {language}<br />
      Currency: {currency.symbol}
    </div>
  );
}

Dynamic Updates

import { useDContext } from '@dynamic-framework/ui-react';

function LanguageSwitcher() {
  const { language, setContext } = useDContext();

  const switchLanguage = (newLang: string) => {
    setContext({ language: newLang });
  };

  return (
    <div>
      <button onClick={() => switchLanguage('en')}>English</button>
      <button onClick={() => switchLanguage('es')}>Español</button>
      <button onClick={() => switchLanguage('fr')}>Français</button>
      <p>Current: {language}</p>
    </div>
  );
}

Custom Icon Library

import { DContextProvider } from '@dynamic-framework/ui-react';

function App() {
  return (
    <DContextProvider
      icon={{
        familyClass: 'material-icons',
        familyPrefix: '',
        materialStyle: true
      }}
      iconMap={{
        x: 'close',
        xLg: 'close',
        chevronDown: 'expand_more',
        chevronUp: 'expand_less',
        chevronLeft: 'chevron_left',
        chevronRight: 'chevron_right',
        upload: 'upload',
        calendar: 'calendar_today',
        check: 'check',
        alert: {
          warning: 'warning',
          danger: 'error',
          success: 'check_circle',
          info: 'info'
        },
        input: {
          search: 'search',
          show: 'visibility',
          hide: 'visibility_off',
          increase: 'add',
          decrease: 'remove'
        }
      }}
    >
      <YourApp />
    </DContextProvider>
  );
}

DPortalContext

A specialized context for managing modal overlays and portals with stacking, animations, and keyboard navigation.

Import

import { DPortalContextProvider, useDPortalContext } from '@dynamic-framework/ui-react';
DPortalContextProvider is automatically rendered by DContextProvider. You typically don’t need to use it directly unless you need multiple independent portal contexts.

Types

type PortalComponent<P = any> = FC<PortalProps<P>>;

type PortalProps<P = unknown> = {
  name: string;
  payload: P;
};

type PortalAvailableList<T extends Record<string, unknown>> = {
  [K in keyof T]: PortalComponent<T[K]>;
};

type PortalContextType<T extends Record<string, unknown>> = {
  stack: PortalStackItem<string, T[keyof T]>[];
  openPortal: (name: string, payload: T[keyof T]) => void;
  closePortal: () => void;
};

Context Value

stack
PortalStackItem[]
Array of currently open portals in order (oldest to newest)
openPortal
function
Opens a new portal and adds it to the stack
(name: string, payload: any) => void
name
string
required
The portal name (must match a key in availablePortals)
payload
any
Data to pass to the portal component
closePortal
function
Closes the topmost portal in the stack
() => void

Usage

Define Portal Components

import type { PortalProps } from '@dynamic-framework/ui-react';

type ConfirmDialogPayload = {
  title: string;
  message: string;
  onConfirm: () => void;
};

function ConfirmDialog({ payload }: PortalProps<ConfirmDialogPayload>) {
  const { closePortal } = useDPortalContext();

  const handleConfirm = () => {
    payload.onConfirm();
    closePortal();
  };

  return (
    <div className="portal">
      <div className="modal">
        <h2>{payload.title}</h2>
        <p>{payload.message}</p>
        <button onClick={handleConfirm}>Confirm</button>
        <button onClick={closePortal}>Cancel</button>
      </div>
    </div>
  );
}

type ImageViewerPayload = {
  imageUrl: string;
  alt: string;
};

function ImageViewer({ payload }: PortalProps<ImageViewerPayload>) {
  const { closePortal } = useDPortalContext();

  return (
    <div className="portal" onClick={closePortal}>
      <img src={payload.imageUrl} alt={payload.alt} />
    </div>
  );
}

Register Portals

import { DContextProvider } from '@dynamic-framework/ui-react';

type AvailablePortals = {
  confirm: ConfirmDialogPayload;
  imageViewer: ImageViewerPayload;
};

function App() {
  return (
    <DContextProvider
      availablePortals={{
        confirm: ConfirmDialog,
        imageViewer: ImageViewer
      }}
    >
      <YourApp />
    </DContextProvider>
  );
}

Open Portals

import { useDPortalContext } from '@dynamic-framework/ui-react';

function DeleteButton({ itemId }) {
  const { openPortal } = useDPortalContext<AvailablePortals>();

  const handleDelete = () => {
    openPortal('confirm', {
      title: 'Delete Item',
      message: 'Are you sure you want to delete this item?',
      onConfirm: () => {
        // Delete logic
        console.log('Deleting item:', itemId);
      }
    });
  };

  return <button onClick={handleDelete}>Delete</button>;
}

function ImageGallery({ images }) {
  const { openPortal } = useDPortalContext<AvailablePortals>();

  return (
    <div>
      {images.map(img => (
        <img
          key={img.id}
          src={img.thumbnail}
          alt={img.alt}
          onClick={() => openPortal('imageViewer', {
            imageUrl: img.full,
            alt: img.alt
          })}
        />
      ))}
    </div>
  );
}

Nested Portals

function SettingsPortal({ payload }: PortalProps<SettingsPayload>) {
  const { openPortal, closePortal } = useDPortalContext();

  const handleReset = () => {
    // Open a confirmation portal on top of the settings portal
    openPortal('confirm', {
      title: 'Reset Settings',
      message: 'This will reset all settings to defaults.',
      onConfirm: () => {
        // Reset logic
        closePortal(); // Close confirmation
        closePortal(); // Close settings
      }
    });
  };

  return (
    <div className="portal">
      <h2>Settings</h2>
      <button onClick={handleReset}>Reset to Defaults</button>
      <button onClick={closePortal}>Close</button>
    </div>
  );
}

Features

Automatic Body Scroll Lock

When portals are open, body scrolling is automatically disabled to prevent background scrolling.

Keyboard Navigation

  • Escape: Closes the topmost portal (if not marked with data-bs-backdrop)
  • Tab: Keyboard focus is trapped within the active portal
  • Shift+Tab: Reverse tab order within portal

Backdrop Click

Clicking the backdrop automatically closes the portal unless the portal element has data-bs-backdrop attribute.
function ModalWithBackdrop({ payload }: PortalProps) {
  return (
    <div className="portal" data-bs-backdrop>
      {/* Backdrop clicks won't close this modal */}
    </div>
  );
}

Animations

Portals use Framer Motion for smooth enter/exit animations:
  • Backdrop fades in/out
  • Portal content can add custom animations
  • Exit animations complete before portal is removed

Portal DOM Structure

Portals are rendered into a container element:
<div id="d-portal">
  <!-- Backdrop -->
  <div class="backdrop" style="opacity: 0.5"></div>
  <!-- Portal Content -->
  <div class="portal">
    <!-- Your portal component -->
  </div>
</div>
Make sure to add the portal container to your HTML:
<!DOCTYPE html>
<html>
  <body>
    <div id="root"></div>
    <div id="d-portal"></div>
  </body>
</html>

Build docs developers (and LLMs) love