modal
lobehub/lobe-chat
LobeHub imperative modal conventions for createModal, confirmModal, and useModalContext patterns.
What is modal?
Standardized approach for building modals, dialogs, and confirm flows in LobeHub using imperative APIs. Use this when creating or migrating modal implementations to follow LobeHub's base-ui modal stack conventions.
- Provides imperative modal creation via createModal and confirmModal functions
- Enables modal content components to access close and dismiss controls via useModalContext
- Establishes file structure and patterns for modal features (content component + factory function)
- Supports both modern base-ui modals (@lobehub/ui/base-ui) and legacy antd-based modals (@lobehub/ui)
- Integrates with i18n for modal titles and content translations
- Offers semantic styling options (backdrop, popup, header, content) instead of antd-specific style keys
How to install modal
npx skills add https://github.com/lobehub/lobe-chat --skill modal- @lobehub/ui/base-ui package installed (for recommended approach)
- ModalHost component mounted near app root (required for createModal to render)
- react-i18next for translations in modal content
How to use modal
- 1.Create a content component (MyFeatureContent.tsx) that uses useModalContext to access close()
- 2.Create a factory function (index.tsx) that calls createModal with title, content, width, and other options
- 3.Import and call the factory function (e.g., createMyFeatureModal()) from event handlers
- 4.Use useTranslation in content components and import { t } from 'i18next' in factory functions for i18n
- 5.Ensure ModalHost from @lobehub/ui/base-ui is mounted at app root if not already present
Use cases
- Creating a new settings or configuration modal with custom form content
- Migrating existing declarative modals (with open state) to imperative createModal calls
- Building confirmation dialogs with async onOk handlers
- Implementing feature-specific modals that need to close themselves via useModalContext
- Styling modals with consistent width, mask behavior, and footer options across the app
- Frontend developers building features in LobeHub/lobe-chat
- Teams migrating from declarative to imperative modal patterns
- Developers maintaining modal consistency across a large codebase
modal FAQ
Imperative (createModal) is recommended. It eliminates local open/close state management and simplifies component logic compared to declarative <Modal open={state} /> patterns.
@lobehub/ui/base-ui is the modern headless approach (preferred for new code); @lobehub/ui uses antd Modal props and is considered legacy. Migrate new work to base-ui.
Ensure ModalHost from @lobehub/ui/base-ui is mounted once near your app root. Without it, createModal calls will not render.
Use useTranslation in content components; in factory functions where hooks unavailable, import { t } from 'i18next' and call t('key', { ns: 'namespace' }).
Set maskClosable: true in createModal options. You can also control this dynamically via setCanDismissByClickOutside from useModalContext.
Full instructions (SKILL.md)
Source of truth, from lobehub/lobe-chat.
name: modal description: 'LobeHub imperative modal conventions. Use when creating or migrating modals, dialogs, popups, confirm flows, ModalHost wiring, createModal, confirmModal, useModalContext, or base-ui modal APIs.' user-invocable: false
Modal Imperative API Guide
Recommended: @lobehub/ui/base-ui
New code should use the base-ui modal stack (headless primitives, not antd Modal):
createModal,confirmModal,ModalHostfrom@lobehub/ui/base-uiuseModalContextfrom@lobehub/ui/base-uiinside modal content
Body slot: pass content (or children; runtime uses content ?? children).
Global ModalHost (required)
Base-ui createModal renders through a separate host from the root package. The app must mount ModalHost from @lobehub/ui/base-ui once near the root (e.g. next to other global hosts). Without it, createModal calls will not appear.
If the project only mounts ModalHost from @lobehub/ui, add a second lazy ModalHost from @lobehub/ui/base-ui until all imperative modals are migrated.
Why imperative?
| Mode | Characteristics | Recommended |
|---|---|---|
| Declarative | open state + <Modal /> | ❌ |
| Imperative | Call createModal(), no local state | ✅ |
File structure
features/
└── MyFeatureModal/
├── index.tsx # export createXxxModal
└── MyFeatureContent.tsx # modal body
1. Content (MyFeatureContent.tsx)
'use client';
import { useModalContext } from '@lobehub/ui/base-ui';
import { useTranslation } from 'react-i18next';
export const MyFeatureContent = () => {
const { t } = useTranslation('namespace');
const { close } = useModalContext();
return <div>{/* ... */}</div>;
};
2. createModal (index.tsx)
'use client';
import { createModal } from '@lobehub/ui/base-ui';
import { t } from 'i18next';
import { MyFeatureContent } from './MyFeatureContent';
export const createMyFeatureModal = () =>
createModal({
content: <MyFeatureContent />,
footer: null,
maskClosable: true,
styles: {
content: { overflow: 'hidden', padding: 0 },
},
title: t('myFeature.title', { ns: 'setting' }),
width: 'min(80%, 800px)',
});
3. Usage
import { createMyFeatureModal } from '@/features/MyFeatureModal';
const handleOpen = useCallback(() => {
createMyFeatureModal();
}, []);
return <Button onClick={handleOpen}>Open</Button>;
i18n
- Content:
useTranslationin components. createModaloptions:import { t } from 'i18next'where hooks are unavailable.
useModalContext
const { close, setCanDismissByClickOutside } = useModalContext();
Common options (base-ui)
ImperativeModalProps builds on BaseModalProps: title, width, maskClosable, open, onOpenChange, footer, styles / classNames (keys: backdrop, popup, header, title, close, content, …).
| Property | Notes |
|---|---|
content | Main body (preferred name vs children) |
maskClosable | Click outside to dismiss |
styles.* | Semantic regions, not antd styles.body |
Confirm
import { confirmModal } from '@lobehub/ui/base-ui';
confirmModal({
title: '…',
content: '…',
okText: '…',
cancelText: '…',
onOk: async () => {},
});
Legacy: @lobehub/ui (root)
Older call sites use createModal from @lobehub/ui, which is typed as antd Modal props (children, allowFullscreen, getContainer, destroyOnHidden, styles.body, etc.). Prefer migrating new work to @lobehub/ui/base-ui.
Examples (legacy): src/features/SkillStore/index.tsx, src/features/LibraryModal/CreateNew/index.tsx.
Examples
- Base-ui (preferred): follow sections above; ensure base-ui
ModalHostis mounted. - Legacy:
src/features/SkillStore/index.tsx,src/features/LibraryModal/CreateNew/index.tsx
Related skills
More from lobehub/lobe-chat and the wider catalog.

project-overview
LobeHub monorepo architecture map for navigating code layers, packages, and project structure.

react
LobeHub React component conventions for TSX UI, styling, routing, and state management.

testing
Vitest testing guide for writing, fixing, and debugging tests in LobeHub projects.

typescript
LobeHub TypeScript style and type-safety guide for consistent, type-safe code.

zustand
LobeHub Zustand state management conventions for store slices, actions, and optimistic updates.

add-provider-doc
Add documentation for a new AI provider with usage guides, environment variables, Docker config, and image resources.