Skip to Content
FrontendBundlesCRUDModal Components

Modal Components

The CRUD bundle provides a comprehensive set of modal dialog components for various user interactions including confirmations, quick actions, data imports, and content management. All modals use the DefaultModalSkin wrapper for consistent styling and behavior.


Core Architecture

DefaultModalSkin

All modal components use the DefaultModalSkin wrapper which provides consistent styling and behavior:

interface DefaultModalSkinProps { title?: string | React.ReactNode; // Modal title isOpen: boolean; // Controls modal visibility onClose: () => void; // Close handler children: React.ReactNode; // Modal content isModal?: boolean; // Modal behavior (default: true) locale?: string; // Locale for translations }

Features

  • Accessible: Full ARIA support and keyboard navigation
  • Responsive: Mobile-friendly design
  • Customizable: Support for custom titles and content
  • Auto-focus: Manages focus for accessibility
  • Overlay: Click outside to close
  • Scrollable: Handles overflow content

Component Overview

1. ConfirmationModal

Simple confirmation dialog for destructive or important actions.

Props

type ConfirmationModalProps = { resource: string; // API resource name isOpen: boolean; // Modal visibility onClose: () => void; // Close handler action: string; // Action type (delete, archive, etc.) id?: number; // Target item ID onConfirm: () => void; // Confirmation handler locale?: string; // Locale for translations }

Features

  • Customizable Actions: Support for any action type
  • Icon Integration: Dynamic icons based on action
  • Color Coding: Appropriate colors for different actions
  • Keyboard Support: Enter to confirm, Esc to cancel

Usage Example

import { ConfirmationModal } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function UserManagement() { const [deleteModal, setDeleteModal] = useState({ isOpen: false, userId: null }); const handleDelete = (userId: number) => { setDeleteModal({ isOpen: true, userId: userId }); }; const confirmDelete = async () => { try { await deleteUser(deleteModal.userId); toast.success("User deleted successfully!"); setDeleteModal({ isOpen: false, userId: null }); refetchUsers(); } catch (error) { toast.error("Failed to delete user"); } }; return ( <> <Button variant="destructive" onClick={() => handleDelete(user.id)} > Delete User </Button> <ConfirmationModal resource="users" isOpen={deleteModal.isOpen} onClose={() => setDeleteModal({ isOpen: false, userId: null })} action="delete" id={deleteModal.userId} onConfirm={confirmDelete} locale="en" /> </> ); }

2. QuickAddModal

Modal for quickly adding new entities without leaving the current page.

Props

type QuickAddModalProps = { resource: string; // API resource name onClose: () => void; // Close handler isOpen: boolean; // Modal visibility formInputs: FilterField[]; // Form field definitions locale?: string; // Locale for translations csrfJwt: string; // CSRF token tenant: string; // Tenant identifier }

Features

  • Dynamic Form: Renders form based on field configuration
  • Real-time Validation: Live form validation with error display
  • Auto-refresh: Updates parent listing after successful creation
  • Keyboard Shortcuts: Ctrl+Enter to submit
  • Form Reset: Clears form after successful submission

Usage Example

import { QuickAddModal, ListingContextProvider } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; const quickAddFields: FilterField[] = [ { key: "name", label: "Name", type: ColumnTypeEnum.TEXT, required: true, placeholder: "Enter name" }, { key: "email", label: "Email", type: ColumnTypeEnum.EMAIL, required: true, placeholder: "user@example.com" }, { key: "status", label: "Status", type: ColumnTypeEnum.SELECT, options: [ {label: "Active", value: "active"}, {label: "Inactive", value: "inactive"} ], defaultValue: "active" } ]; function UserListing() { const [quickAddOpen, setQuickAddOpen] = useState(false); return ( <ListingContextProvider> <div className="space-y-4"> <Button onClick={() => setQuickAddOpen(true)}> Quick Add User </Button> <QuickAddModal resource="users" isOpen={quickAddOpen} onClose={() => setQuickAddOpen(false)} formInputs={quickAddFields} csrfJwt={csrfToken} tenant={tenant} locale="en" /> {/* Your listing table here */} </div> </ListingContextProvider> ); }

3. QuickEdit

Modal for quickly editing existing entities inline within listings.

Props

interface QuickEditProps { resource: string; // API resource name onClose: () => void; // Close handler isOpen: boolean; // Modal visibility id: number; // Entity ID to edit formInputs: FilterField[]; // Form field definitions locale?: string; // Locale for translations tenant: string; // Tenant identifier csrfJwt: string; // CSRF token }

Features

  • Pre-populated Fields: Automatically loads existing entity data
  • Patch Updates: Only sends changed fields to reduce payload
  • Real-time Updates: Updates listing table immediately after save
  • Error Handling: Comprehensive error display and recovery
  • Optimistic Updates: UI updates before API confirmation

Usage Example

import { QuickEdit } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function UserListingActions({ user }: { user: any }) { const [quickEditOpen, setQuickEditOpen] = useState(false); const editFields: FilterField[] = [ { key: "name", label: "Name", type: ColumnTypeEnum.TEXT, required: true }, { key: "status", label: "Status", type: ColumnTypeEnum.SELECT, options: [ {label: "Active", value: "active"}, {label: "Inactive", value: "inactive"} ] } ]; return ( <> <Button size="sm" variant="outline" onClick={() => setQuickEditOpen(true)} > Quick Edit </Button> <QuickEdit resource="users" isOpen={quickEditOpen} onClose={() => setQuickEditOpen(false)} id={user.id} formInputs={editFields} tenant={tenant} csrfJwt={csrfToken} locale="en" /> </> ); }

4. ImportModal

Modal for bulk data import with CSV/Excel file support and preview functionality.

Props

interface ImportModalProps { resource: string; // API resource name onClose: () => void; // Close handler isOpen: boolean; // Modal visibility fqcn_bui: IFQCN_BUI; // Component configuration onImportComplete?: (data: any) => void; // Success callback qField?: string; // Query field for updates locale?: string; // Locale for translations user?: User; // Current user csrfJwt: string; // CSRF token tenant?: string; // Tenant identifier }

Features

  • File Upload: Drag & drop or click to upload
  • Format Support: CSV and Excel files
  • Data Preview: Table preview before import
  • Validation: Real-time data validation
  • Progress Tracking: Import progress indicator
  • Error Reporting: Detailed error messages for failed imports
  • Batch Processing: Handles large datasets efficiently

Usage Example

import { ImportModal } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function UserImport() { const [importModalOpen, setImportModalOpen] = useState(false); const handleImportComplete = (result: any) => { toast.success(`Successfully imported ${result.success_count} users`); if (result.error_count > 0) { toast.warning(`${result.error_count} imports failed`); } // Refresh the listing refetchUsers(); }; return ( <> <Button onClick={() => setImportModalOpen(true)}> Import Users </Button> <ImportModal resource="users" isOpen={importModalOpen} onClose={() => setImportModalOpen(false)} fqcn_bui={{ Bundle: "user", Unit: "management", Interface: "import" }} onImportComplete={handleImportComplete} user={user} csrfJwt={csrfToken} tenant={tenant} locale="en" /> </> ); }

5. TranslationModal

Modal for managing multi-language translations for translatable content.

Props

interface TranslationModalProps { onClose: () => void; // Close handler isOpen: boolean; // Modal visibility word: string; // Text to translate onSave?: (updatedTranslations: {[key: string]: string}) => void; // Save callback locale: string; // Current locale updateTranslations: (translations: {key?: string; value: string}) => void; // Update handler user: User | null; // Current user }

Features

  • Multi-language Support: Manage translations for multiple locales
  • Dynamic Language List: Supports all configured languages
  • Real-time Editing: Live translation editing
  • Auto-save: Automatic saving of translation changes
  • Key-Value Storage: Integrates with KVS for persistence

Usage Example

import { TranslationModal } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function TranslatableContent() { const [translationModal, setTranslationModal] = useState({ isOpen: false, word: "" }); const openTranslationModal = (word: string) => { setTranslationModal({ isOpen: true, word: word }); }; const updateTranslations = (translation: any) => { // Handle translation update console.log("Translation updated:", translation); // Update your state or refetch data }; return ( <> <div className="translatable-content"> <span onClick={() => openTranslationModal("Welcome Message")} className="cursor-pointer hover:bg-yellow-100" > {t("Welcome Message")} <HiOutlineTranslate className="inline ml-1" /> </span> </div> <TranslationModal isOpen={translationModal.isOpen} onClose={() => setTranslationModal({ isOpen: false, word: "" })} word={translationModal.word} locale="en" updateTranslations={updateTranslations} user={user} /> </> ); }

6. ImageModal

Modal for viewing and managing images with full-screen display.

Props

interface ImageModalProps { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler imageUrl: string; // Image URL to display imageAlt?: string; // Alt text for accessibility title?: string; // Modal title actions?: React.ReactNode; // Custom action buttons }

Features

  • Full-screen View: Large image display with zoom
  • Navigation: Previous/next for image galleries
  • Download: Direct image download
  • Responsive: Mobile-optimized viewing
  • Accessibility: Full screen reader support

Usage Example

import { ImageModal } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function ProductGallery({ product }: { product: any }) { const [imageModal, setImageModal] = useState({ isOpen: false, imageUrl: "", title: "" }); const openImageModal = (imageUrl: string, title: string) => { setImageModal({ isOpen: true, imageUrl, title }); }; return ( <> <div className="grid grid-cols-3 gap-4"> {product.images.map((image: any, index: number) => ( <img key={index} src={image.thumbnail} alt={image.alt} className="cursor-pointer rounded-lg hover:opacity-80" onClick={() => openImageModal(image.full_size, image.title)} /> ))} </div> <ImageModal isOpen={imageModal.isOpen} onClose={() => setImageModal({ isOpen: false, imageUrl: "", title: "" })} imageUrl={imageModal.imageUrl} title={imageModal.title} imageAlt="Product image" actions={ <Button variant="outline"> Download Image </Button> } /> </> ); }

7. HelpModal

Modal for displaying contextual help and documentation.

Props

interface HelpModalProps { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler title?: string; // Help section title content: React.ReactNode; // Help content searchable?: boolean; // Enable content search locale?: string; // Locale for translations }

Features

  • Rich Content: Support for markdown and HTML content
  • Search: Find content within help documentation
  • Navigation: Jump to specific sections
  • Print Support: Print help content
  • Responsive: Mobile-friendly help display

8. QuickShowModal

Modal for quickly previewing entity details without leaving the listing.

Props

type QuickShowModalProps = { resource: string; // API resource name onClose: () => void; // Close handler isOpen: boolean; // Modal visibility id: number; // Entity ID to preview fields?: DisplayField[]; // Fields to display locale?: string; // Locale for translations tenant: string; // Tenant identifier csrfJwt: string; // CSRF token }

9. DefaultFlagModal

Modal for setting an entity as the default or flagged item.

Props

type DefaultFlagModalProps = { resource: string; // API resource name isOpen: boolean; // Modal visibility onClose: () => void; // Close handler id: number; // Entity ID currentDefault?: number; // Current default ID onConfirm: () => void; // Confirmation handler locale?: string; // Locale for translations }

10. AddFilterModal

Modal for adding and configuring custom filters.

Props

type AddFilterModalProps = { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler availableFields: FilterField[]; // Available filter fields onAddFilter: (filter: FilterField) => void; // Add filter callback locale?: string; // Locale for translations }

11. FullDuplicateModal

Modal for duplicating an entity with all its related data.

Props

type FullDuplicateModalProps = { resource: string; // API resource name isOpen: boolean; // Modal visibility onClose: () => void; // Close handler id: number; // Entity ID to duplicate includeRelations?: boolean; // Include related entities onSuccess?: (newId: number) => void; // Success callback locale?: string; // Locale for translations tenant: string; // Tenant identifier csrfJwt: string; // CSRF token }

12. DetailedPrintModal

Modal for configuring and generating print output.

Props

type DetailedPrintModalProps = { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler data: any; // Data to print template?: string; // Print template orientation?: 'portrait' | 'landscape'; // Page orientation locale?: string; // Locale for translations }

13. DetailedEmailModal

Modal for composing and sending emails related to an entity.

Props

type DetailedEmailModalProps = { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler resource: string; // API resource name id: number; // Entity ID defaultRecipients?: string[]; // Default email recipients onSend?: (emailData: any) => void; // Send callback locale?: string; // Locale for translations tenant: string; // Tenant identifier csrfJwt: string; // CSRF token }

14. EditListingImportModal

Modal for editing import configurations during the import process.

Props

type EditListingImportModalProps = { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler importConfig: ImportConfig; // Current import configuration onSave: (config: ImportConfig) => void; // Save callback locale?: string; // Locale for translations }

15. FormFieldsRenderer

A modal component that renders form fields dynamically.

Props

type FormFieldsRendererProps = { isOpen: boolean; // Modal visibility onClose: () => void; // Close handler fields: FilterField[]; // Fields to render onSubmit: (data: any) => void; // Submit callback title?: string; // Modal title locale?: string; // Locale for translations }

ModalPurposeKey Features
ConfirmationModalConfirm actionsCustomizable actions, keyboard support
QuickAddModalCreate entitiesDynamic forms, real-time validation
QuickEditEdit entitiesPre-populated fields, patch updates
QuickShowModalPreview entitiesFast preview without navigation
ImportModalBulk importCSV/Excel support, validation
TranslationModalManage translationsMulti-language support
ImageModalView imagesFull-screen, zoom, download
HelpModalShow helpSearchable content
DefaultFlagModalSet defaultsFlag/unflag entities
AddFilterModalAdd filtersCustom filter configuration
FullDuplicateModalDuplicate entitiesInclude/exclude relations
DetailedPrintModalPrint configurationTemplates, orientation
DetailedEmailModalSend emailsRecipients, templates
EditListingImportModalEdit importsModify import configuration
FormFieldsRendererDynamic formsRender any field configuration

Advanced Usage Patterns

Combine multiple modals for complex workflows:

function UserWorkflow() { const [currentModal, setCurrentModal] = useState<'add' | 'confirm' | 'success' | null>(null); const [newUserId, setNewUserId] = useState<number | null>(null); const handleUserCreated = (userData: any) => { setNewUserId(userData.id); setCurrentModal('confirm'); }; const handleConfirmComplete = () => { setCurrentModal('success'); }; return ( <> <Button onClick={() => setCurrentModal('add')}> Add User </Button> <QuickAddModal resource="users" isOpen={currentModal === 'add'} onClose={() => setCurrentModal(null)} formInputs={userFields} onSuccess={handleUserCreated} csrfJwt={csrfToken} tenant={tenant} /> <ConfirmationModal resource="users" isOpen={currentModal === 'confirm'} onClose={() => setCurrentModal(null)} action="send_welcome_email" id={newUserId} onConfirm={handleConfirmComplete} /> <DefaultModalSkin isOpen={currentModal === 'success'} onClose={() => setCurrentModal(null)} title="Success" > <div className="text-center py-8"> <IoCheckmarkCircleOutline className="mx-auto text-green-500 text-6xl mb-4" /> <h3 className="text-lg font-semibold mb-2">User Created Successfully!</h3> <p className="text-gray-600">Welcome email has been sent.</p> </div> </DefaultModalSkin> </> ); }

Best Practices

Accessibility

  • Always provide meaningful titles and descriptions
  • Use proper ARIA labels and roles
  • Ensure keyboard navigation works correctly
  • Test with screen readers

Performance

  • Lazy load modal content when possible
  • Clean up event listeners on unmount
  • Avoid rendering heavy content in closed modals
  • Use React.memo for expensive modal content

Custom Modal Creation

Create custom modals using the DefaultModalSkin wrapper:

import { DefaultModalSkin } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function CustomModal({ isOpen, onClose }: { isOpen: boolean, onClose: () => void }) { return ( <DefaultModalSkin isOpen={isOpen} onClose={onClose} title="Custom Modal" > <div className="space-y-4"> <p>Your custom content here</p> <div className="flex justify-end gap-2"> <Button variant="outline" onClick={onClose}> Cancel </Button> <Button onClick={handleCustomAction}> Confirm </Button> </div> </div> </DefaultModalSkin> ); }

This comprehensive documentation covers all modal components with their props, usage patterns, and advanced implementation examples.

Last updated on