
Modal
Create or migrate LobeChat-style imperative modals with createModal, confirmModal, and base-ui ModalHost instead of antd open-state dialogs.
Overview
modal is an agent skill for the Build phase that implements LobeHub imperative modals with base-ui createModal, confirmModal, and ModalHost wiring.
Install
npx skills add https://github.com/lobehub/lobe-chat --skill modalWhat is this skill?
- Mandates @lobehub/ui/base-ui stack (createModal, confirmModal, ModalHost, useModalContext)—not antd declarative Modal
- Documents dual ModalHost requirement: base-ui host at app root or createModal calls never surface
- Compares declarative open-state modals (discouraged) vs imperative createModal (recommended)
- Specifies content slot via content prop with children fallback in modal body
- Feature-folder layout: MyFeatureModal/index.tsx exporting createXxxModal factory
- Two modal modes documented: declarative open+Modal (not recommended) vs imperative createModal (recommended)
- Requires global ModalHost from @lobehub/ui/base-ui at app root for createModal visibility
Adoption & trust: 816 installs on skills.sh; 78.4k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are adding dialogs in LobeChat but declarative open flags and the wrong ModalHost leave modals missing or split across two host systems.
Who is it for?
Developers customizing LobeChat or LobeHub UI apps who need consistent imperative modal APIs and migration off antd Modal.
Skip if: Greenfield React apps without @lobehub/ui, native mobile dialogs, or teams standardizing on a different design system entirely.
When should I use this skill?
Creating or migrating modals, dialogs, popups, confirm flows, ModalHost wiring, createModal, confirmModal, useModalContext, or base-ui modal APIs in LobeHub projects.
What do I get? / Deliverables
Features export createXxxModal factories, mount the base-ui ModalHost at the root, and render confirms and dialogs imperatively without local open state.
- Feature module exporting createXxxModal (and confirm flows where needed)
- Root-level base-ui ModalHost configuration documented or added
Recommended Skills
Journey fit
How it compares
LobeHub-specific modal skill—not a generic Radix or MUI dialog generator.
Common Questions / FAQ
Who is modal for?
Contributors and indie builders working in lobe-chat or LobeHub UI codebases who want agents to follow official imperative modal patterns.
When should I use modal?
During Build frontend when creating or migrating modals, dialogs, confirm flows, ModalHost wiring, createModal, confirmModal, or useModalContext with base-ui APIs.
Is modal safe to install?
It is in-repo procedural documentation without extra tool permissions listed; review the Security Audits panel on this Prism page and the lobehub/lobe-chat source before agent-driven refactors.
SKILL.md
READMESKILL.md - Modal
# 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`, `ModalHost` from `@lobehub/ui/base-ui` - `useModalContext` from `@lobehub/ui/base-ui` inside 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`) ```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`) ```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 ```tsx import { createMyFeatureModal } from '@/features/MyFeatureModal'; const handleOpen = useCallback(() => { createMyFeatureModal(); }, []); return <Button onClick={handleOpen}>Open</Button>; ``` ### i18n - **Content**: `useTranslation` in components. - **`createModal` options**: `import { t } from 'i18next'` where hooks are unavailable. ### `useModalContext` ```tsx 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 ```tsx 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): foll