# Dynamic Framework Components
Dynamic Framework offers more than 46 specialized React components for the financial industry, designed to cover the most common needs in banking and financial applications.
# Component Catalog
Explore all components interactively in our Storybook (opens new window).
# Layout Components
- DBox: Container with flexible styling options
- DCard: Card container with Header, Body, and Footer sub-components
- DLayout: Page layout system with LayoutPane for responsive designs
- DCollapse: Collapsible content sections (supports controlled and uncontrolled modes)
# Navigation Components
- DTabs: Tab navigation with DTabContent for panel switching
- DStepper: Multi-step navigation (with DStepperDesktop and DStepperMobile variants)
- DPaginator: Pagination control for listings
# Form Components
- DInput: Text input with validation states
- DInputSearch: Search input with built-in debounce (reintroduced in v2.6)
- DInputCheck: Checkbox input
- DInputSwitch: Toggle switch input
- DInputCounter: Numeric counter with increment/decrement
- DInputCurrency: Currency-formatted input
- DInputMask: Masked input for formatted data
- DInputPassword: Password input with visibility toggle
- DInputPhone: International phone number input
- DInputPin: PIN/code input with individual digit boxes
- DInputRange: Range slider input
- DInputSelect: Dropdown select input
- DSelect: Advanced select with search (uses react-select)
- DDatePicker: Date picker with calendar
- DPasswordStrengthMeter: Password strength indicator with validation
- DBoxFile: File upload with drag-and-drop
# Data Display Components
- DListGroup: List container with DListGroupItem
- DTimeline: Timeline for event history
- DCarousel: Carousel/slider with DCarouselSlide
- DCurrencyText: Formatted currency display
- DProgress: Progress bar indicator
# Feedback Components
- DAlert: User notification messages
- DModal: Modal dialog with Header, Body, Footer
- DOffcanvas: Slide-out panel with Header, Body, Footer
- DToast: Temporary toast notifications (with DToastContainer)
- DPopover: Contextual popover
- DTooltip: Hover tooltips
- DDropdown: Dropdown menu
# Visual Components
- DAvatar: User avatar display
- DBadge: Status/count badges
- DChip: Compact element for tags/filters
- DButton: Action button with loading state
- DButtonIcon: Icon-only button
- DIcon: Icon component (uses Lucide Icons)
# Specialized Financial Components
- DCreditCard: Credit/debit card display with flip animation
- DVoucher: Voucher/receipt display component
- DOtp: One-time password input
# State & Utility Components
- DDataStateWrapper: Declarative handling of loading/error/empty states when rendering lists (also exports
EmptyState,ErrorState,LoadingState) - DErrorBoundary: Error boundary with a configurable fallback (based on
react-error-boundary)
# Component Usage
All components are imported from @dynamic-framework/ui-react:
import {
DButton,
DCard,
DInput,
DAlert
} from '@dynamic-framework/ui-react';
function MyComponent() {
return (
<DCard>
<DCard.Header>
<h5>Account Details</h5>
</DCard.Header>
<DCard.Body>
<DInput
id="account-name"
label="Account Name"
placeholder="Enter account name"
/>
<DButton color="primary">
Save Changes
</DButton>
</DCard.Body>
</DCard>
);
}
# Component Props
# Common Props
Most components share these common props:
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes |
style | CSSProperties | Inline styles |
id | string | Element ID |
# Color Variants
Components that support colors use the color prop:
<DButton color="primary">Primary</DButton>
<DButton color="secondary">Secondary</DButton>
<DButton color="success">Success</DButton>
<DButton color="danger">Danger</DButton>
<DButton color="warning">Warning</DButton>
<DButton color="info">Info</DButton>
# Size Variants
Components that support sizes use the size prop:
<DButton size="sm">Small</DButton>
<DButton>Default</DButton>
<DButton size="lg">Large</DButton>
# Responsive Sizes (v2.3)
DButton and DBadge accept a responsive object in size with per-breakpoint values (xs, sm, md, lg, xl, xxl), just like DIcon:
<DButton size={{ xs: 'sm', md: 'lg' }} text="Continue" />
<DBadge size={{ xs: 'sm', lg: 'md' }} color="success">Active</DBadge>
# Soft Variant (v2.5)
DButton supports variant="soft", which generates the .btn-soft-{color} class for a subtle-background style. It combines with color and size:
<DButton variant="soft" color="primary" text="Soft action" />
<DButton variant="soft" color="danger" text="Delete" />
# State Components (2.1-2.7)
# DInputSearch
Search input with built-in debounce. Extends DInput (omits onChange/defaultValue/type). Unlike DInput, its onChange returns the string directly, not the event.
Own props:
| Prop | Type | Description |
|---|---|---|
debounceMs | number | Debounce delay (default 300) |
onChange | (value: string) => void | Fires after the debounce, receives the string |
onImmediateChange | (value: string) => void | Fires on every keystroke, no debounce |
value | string | Controlled mode |
defaultValue | string | Uncontrolled mode |
placeholder | string | Placeholder text (default 'Search...') |
import { DInputSearch } from '@dynamic-framework/ui-react';
// Uncontrolled, with default debounce (300ms)
<DInputSearch
label="Search"
placeholder="Search accounts..."
onChange={(value) => fetchResults(value)} // string, after debounce
onImmediateChange={(value) => setQuery(value)} // string, immediate
/>
// Controlled + custom debounce
<DInputSearch
value={query}
debounceMs={500}
onChange={(value) => search(value)}
/>
# DDataStateWrapper
Wraps the rendering of a list and automatically shows loading, error, and empty states. It also exports the EmptyState, ErrorState, and LoadingState sub-components for standalone use.
Props (DDataStateWrapperProps<T>):
| Prop | Type | Description |
|---|---|---|
isLoading | boolean | Loading state |
isError | boolean | Error state |
data | T[] \| undefined | Data to render |
onRetry | () => void | Retry callback |
messages | DDataStateMessages | Customizable { loading?, empty?, error?, retry? } |
renderLoading / renderEmpty / renderError | ReactNode \| (() => ReactNode) | Full override of each state |
children | (data: T[]) => ReactNode | Renders the list with guaranteed data |
import { DDataStateWrapper } from '@dynamic-framework/ui-react';
<DDataStateWrapper
isLoading={query.isLoading}
isError={query.isError}
data={query.data}
onRetry={query.refetch}
messages={{
loading: 'Loading transactions...',
empty: 'No transactions',
error: 'We could not load the transactions',
retry: 'Retry',
}}
>
{(transactions) => (
<DListGroup>
{transactions.map((t) => <DListGroupItem key={t.id}>{t.title}</DListGroupItem>)}
</DListGroup>
)}
</DDataStateWrapper>
Pairs with the TanStack Query pattern. See API Integration.
# DErrorBoundary
Error boundary with a configurable fallback, based on react-error-boundary. The library also exports the useErrorBoundary hook.
Props (DErrorBoundaryProps):
| Prop | Type | Description |
|---|---|---|
name | string | Boundary identifier name |
fallback | (props: FallbackProps) => ReactNode | Override of the default fallback |
onError | (error: unknown, info: ErrorInfo) => void | Callback when an error is caught |
children | ReactNode | Protected content |
import { DErrorBoundary } from '@dynamic-framework/ui-react';
<DErrorBoundary
name="dashboard"
onError={(error, info) => logError(error, info)}
>
<Dashboard />
</DErrorBoundary>
# API Changes to Existing Components (2.1-2.7)
# DVoucher — icon and href (v2.2)
iconacceptsfalse | null | string | Partial<DIconProps>: a Lucide name, aDIconprops object, orfalse/nullto hide it.amount,amountDetails(ReactNode), andtitle(required).- The voucher buttons support
hrefin addition toonClick.
<DVoucher
icon={{ icon: 'CircleCheckBig', color: 'success' }}
title="Payment Successful"
amount="$125.00"
/>
# DOffcanvas — responsive (v2.7)
openFrom: in addition to'start' | 'end' | 'top' | 'bottom', accepts a responsive object{ xs?, sm?, md?, lg?, xl?, xxl? }.width/height: accept any CSS length ('320px','50vw','100%') or aResponsiveProp.
<DOffcanvas
openFrom={{ xs: 'bottom', md: 'end' }}
width={{ xs: '100%', md: '480px' }}
/>
# DCarousel — custom arrows (v2.7)
iconArrowLeft / iconArrowRight accept DIcon props:
<DCarousel
iconArrowLeft={{ icon: 'ArrowLeft', color: 'primary' }}
iconArrowRight={{ icon: 'ArrowRight', color: 'primary' }}
>
{/* slides */}
</DCarousel>
# Hooks Exported by the Library
These hooks are actually exported from @dynamic-framework/ui-react:
import {
// Context hooks
useDContext, // Access DContextProvider values
useDPortalContext, // Access portal context for modals
// Component-specific hooks
useDToast, // Programmatic toast notifications
useConfirmModal, // Programmatic confirmation (requires DConfirmModalContainer)
useTabContext, // Access tab state within DTabs
useErrorBoundary, // Error boundary control (from react-error-boundary)
// Currency hooks
useFormatCurrency, // Currency formatting utilities
useInputCurrency, // Currency input handling
// Responsive hooks
useMediaQuery, // Custom media query detection
useMediaBreakpointUpSm, // Breakpoint detection (sm and up)
useMediaBreakpointUpMd, // Breakpoint detection (md and up)
useMediaBreakpointUpLg, // Breakpoint detection (lg and up)
useMediaBreakpointUpXl, // Breakpoint detection (xl and up)
useMediaBreakpointUpXxl, // Breakpoint detection (xxl and up)
// Utility hooks
useStackState, // Stack-based state management
usePortal, // Portal management
useItemSelection, // List item selection management
} from '@dynamic-framework/ui-react';
# Additional Utilities
import {
getErrorMessage, // Extract error message from unknown errors
} from '@dynamic-framework/ui-react';
Implementation Patterns vs Library Exports
Hooks like useApi, useAccounts, or useFormValidation shown in documentation are implementation patterns you create in your project, NOT exports from the library. See API Integration for pattern examples.
# useConfirmModal — programmatic confirmation
Hook to open a confirmation modal from code. It requires mounting DConfirmModalContainer once near the root (next to DContextProvider) and being inside DContextProvider.
Config (UseConfirmModalConfig):
| Field | Type | Description |
|---|---|---|
title / message | string | Modal title and message |
confirmLabel / cancelLabel | string | Button labels |
confirmColor | 'primary' \| 'danger' \| 'warning' | Confirm button color |
onConfirm | () => void \| Promise<void> | Confirmation callback (required) |
onClose | () => void | Callback on close |
critical | { code: string; codeLabel?: string; inputPlaceholder?: string } | Critical confirmation that requires typing an exact code |
The hook returns { open: () => void }.
import { useConfirmModal, DConfirmModalContainer } from '@dynamic-framework/ui-react';
// 1. Mount the container once (next to DContextProvider)
<DConfirmModalContainer />
// 2. Use the hook
function DeleteAccountButton() {
const confirm = useConfirmModal({
title: 'Delete account',
message: 'This action cannot be undone.',
confirmColor: 'danger',
confirmLabel: 'Delete',
critical: { code: 'DELETE ACCOUNT' }, // the user must type this
onConfirm: async () => { await deleteAccount(); },
});
return <DButton color="danger" text="Delete" onClick={confirm.open} />;
}
# Context Provider
Wrap your application with DContextProvider for global configuration:
import { DContextProvider } from '@dynamic-framework/ui-react';
function App() {
return (
<DContextProvider>
<YourApp />
</DContextProvider>
);
}
# Icon System
Dynamic UI 2.0 uses Lucide Icons (opens new window), a modern, consistent icon library with 1000+ icons. Use the DIcon component to render icons.
Critical: PascalCase Format Required
Icons must use PascalCase format. Using kebab-case will show a "?" placeholder.
# Basic Usage
import { DIcon } from '@dynamic-framework/ui-react';
// ✅ Correct - PascalCase
<DIcon icon="Check" />
<DIcon icon="AlertCircle" />
<DIcon icon="ArrowRight" />
<DIcon icon="CreditCard" />
// ❌ Wrong - kebab-case (will show "?")
<DIcon icon="check" />
<DIcon icon="alert-circle" />
# Icon Sizing
Use the size prop with exact CSS values:
<DIcon icon="Home" size="1rem" /> {/* 16px */}
<DIcon icon="Home" size="1.5rem" /> {/* 24px - default */}
<DIcon icon="Home" size="2rem" /> {/* 32px */}
<DIcon icon="Home" size="48px" /> {/* 48px */}
# Responsive Sizes
Icons support responsive sizing with breakpoint-specific values:
<DIcon
icon="Home"
size={{
xs: "1rem", // Mobile
md: "1.5rem", // Tablet
lg: "2rem" // Desktop
}}
/>
Available breakpoints: xs, sm, md, lg, xl, xxl
# Icon Colors
Icons inherit their color from the parent's color CSS property by default. Use the color prop for theme colors:
<DIcon icon="Check" color="success" />
<DIcon icon="X" color="danger" />
<DIcon icon="AlertCircle" color="warning" />
<DIcon icon="Info" color="info" />
<DIcon icon="Star" color="primary" />
For custom colors, use CSS:
<DIcon icon="Heart" style={{ color: '#e91e63' }} />
# Custom Icons (v2.7)
In addition to Lucide icons, DIcon accepts your own icons in two ways:
1. Pass a React component directly. The icon prop accepts string | IconComponent:
import { MyIconSvg } from './icons';
<DIcon icon={MyIconSvg} />
2. Register icons by name in DContextProvider with the iconRegistry prop:
const iconRegistry = { NMChevron: MyIconSvg };
<DContextProvider iconRegistry={iconRegistry}>
<DIcon icon="NMChevron" /> {/* resolves from the registry */}
<DIcon icon="Home" /> {/* falls back to Lucide */}
</DContextProvider>
The iconRegistry takes precedence over Lucide when the name matches in both. If the name is not in the registry, it falls back to Lucide.
# Finding Icons
Browse all available icons at lucide.dev/icons (opens new window). When you find an icon:
- Note the icon name (e.g.,
arrow-right) - Convert to PascalCase (e.g.,
ArrowRight) - Use in DIcon:
<DIcon icon="ArrowRight" />
# Icons by Category
# Navigation
Home, Menu, X, ChevronLeft, ChevronRight, ChevronUp, ChevronDown, ArrowLeft, ArrowRight, ExternalLink, MoreHorizontal, MoreVertical
# Actions
Plus, Minus, Check, X, Edit, Pencil, Trash2, Copy, Download, Upload, Share, Send, Save, RefreshCw
# User & Account
User, Users, UserPlus, UserMinus, UserCheck, LogIn, LogOut, Key, Lock, Unlock, Shield, Settings
# Communication
Mail, MessageSquare, MessageCircle, Phone, Bell, BellOff, AtSign
# Media
Image, Camera, Video, Play, Pause, Volume2, VolumeX, Mic, MicOff
# Files & Data
File, FileText, Folder, FolderOpen, Archive, Clipboard, Database
# Financial (Banking Apps)
CreditCard, Wallet, DollarSign, Banknote, PiggyBank, TrendingUp, TrendingDown, BarChart, PieChart, Receipt, Calculator
# Status & Feedback
AlertCircle, AlertTriangle, Info, HelpCircle, CheckCircle, XCircle, Clock, Loader
# Misc
Search, Filter, Calendar, MapPin, Globe, Link, Eye, EyeOff, Star, Heart, ThumbsUp, ThumbsDown
# Icons in Buttons
Use DButtonIcon for icon-only buttons with proper accessibility:
import { DButtonIcon } from '@dynamic-framework/ui-react';
<DButtonIcon icon="Pencil" ariaLabel="Edit item" />
<DButtonIcon icon="Trash2" ariaLabel="Delete item" color="danger" />
<DButtonIcon icon="Plus" ariaLabel="Add new" variant="outline" />
For buttons with both icon and text, use DButton with iconStart or iconEnd:
import { DButton } from '@dynamic-framework/ui-react';
<DButton iconStart="Plus">Add Account</DButton>
<DButton iconEnd="ArrowRight">Continue</DButton>
<DButton iconStart="Download" iconEnd="ChevronDown">Export</DButton>
# DSelect Critical Usage Pattern
Common Mistake
DSelect uses react-select internally and requires a specific value/onChange pattern. Using e.target.value will NOT work.
# Correct Pattern
import { DSelect } from '@dynamic-framework/ui-react';
// Options must be objects with value and label
const options = [
{ value: 'usd', label: 'US Dollar' },
{ value: 'eur', label: 'Euro' },
{ value: 'gbp', label: 'British Pound' },
];
function CurrencySelect() {
// State holds the full option object, not just the value
const [selected, setSelected] = useState<{ value: string; label: string } | null>(null);
return (
<DSelect
id="currency"
label="Select Currency"
options={options}
value={selected} // Full option object or null
onChange={(option) => setSelected(option)} // Receives full option object
/>
);
}
# What NOT to Do
// ❌ Wrong - Using e.target.value (doesn't work with DSelect)
onChange={(e) => setValue(e.target.value)}
// ❌ Wrong - Passing just the value string
value={selectedValue} // Should be the full option object
// ❌ Wrong - Options as simple strings
options={['USD', 'EUR', 'GBP']} // Must be { value, label } objects
# DSelect vs DInputSelect
| Component | Use Case | Value Format |
|---|---|---|
DSelect | Advanced select with search | { value, label } object |
DInputSelect | Simple dropdown | String value with e.target.value |
# DCollapse Usage Patterns
DCollapse is a controlled component that uses collapsed and onChange props. You must manage the open/closed state externally.
# Basic Usage
import { useState } from 'react';
import { DCollapse, DButton } from '@dynamic-framework/ui-react';
function CollapseExample() {
const [collapsed, setCollapsed] = useState(false);
return (
<div>
<DButton
text={collapsed ? 'Show Details' : 'Hide Details'}
onClick={() => setCollapsed(!collapsed)}
/>
<DCollapse collapsed={collapsed} onChange={setCollapsed}>
<div className="p-3 border mt-2">
<h6>Additional Information</h6>
<p>This content can be collapsed to save space.</p>
</div>
</DCollapse>
</div>
);
}
# Accordion Pattern
function FAQ({ items }: { items: { question: string; answer: string }[] }) {
const [openIndex, setOpenIndex] = useState<number | null>(null);
return (
<div>
{items.map((item, index) => (
<div key={index}>
<button onClick={() => setOpenIndex(openIndex === index ? null : index)}>
{item.question}
</button>
<DCollapse
collapsed={openIndex !== index}
onChange={(c) => {
if (!c) setOpenIndex(index);
else setOpenIndex(null);
}}
>
<div className="p-3">{item.answer}</div>
</DCollapse>
</div>
))}
</div>
);
}
Controlled Component
DCollapse requires state management. Using <DCollapse>Content</DCollapse> without collapsed and onChange props will not work.
# Accessibility
Dynamic Framework components are designed with accessibility in mind and follow WAI-ARIA (opens new window) standards. However, the library cannot make your application fully accessible on its own—you must take action to ensure accessibility.
# What the Components Provide
| Component | Built-in Accessibility |
|---|---|
| DInput | Connects label with input automatically via id |
| DButton | Keyboard focus, aria-busy for loading states |
| DModal | Focus trap, aria-modal, Escape to close |
| DSelect | aria-expanded, arrow key navigation |
| DAlert | role="alert" for screen reader announcements |
# Your Responsibility
You must provide the necessary props for full accessibility:
- Inputs: Always provide
labeloraria-label - Buttons: Provide
textoraria-labelfor icon-only buttons - Images: Always include descriptive
alttext
// ✅ Accessible input
<DInput id="search" label="Search accounts" />
// ✅ Accessible icon-only button
<DButtonIcon icon="Trash2" ariaLabel="Delete item" />
# Documentation and Support
Each component includes interactive documentation in our Storybook:
- Detailed documentation of props and methods
- Interactive code examples
- Best practice guides
Access complete documentation at react.dynamicframework.dev (opens new window)