@buildkitgg/shadcn-modals-manager
v1.1.4
Published
Typed shadcn modal management with default components and optional Base UI or Radix adapters.
Maintainers
Readme
@buildkitgg/shadcn-modals-manager
Managed shadcn dialogs with a default renderer and optional Base UI or Radix registry components.
pnpm add @buildkitgg/shadcn-baseui-kit@npm:@buildkitgg/shadcn-baseui-vega
pnpm add @buildkitgg/shadcn-modals-manager react react-domimport { createModalManager, ModalRenderer } from "@buildkitgg/shadcn-modals-manager"
import "@buildkitgg/shadcn-modals-manager/styles.css"
export const modals = createModalManager()
export function App() {
return <ModalRenderer manager={modals} />
}
const confirmed = await modals.confirm({ title: "Delete draft?" })The default renderer uses @buildkitgg/shadcn-baseui-kit, which the app supplies as a peer dependency. Import the
stylesheet once; it provides the kit's tokens and compiled utilities without a global reset. If your app already loads
the kit's styles, no second import is needed. Override the shadcn CSS variables to apply your theme. React and React DOM
are peers.
Switching UI libraries
@buildkitgg/fluentui-modals-manager exports the same createModalManager, ModalRenderer, manager types and renderer
props. Standard modal code needs only a package import change. Both renderers take manager; neither requires a
primitive or components prop. surfaceProps supports the shared className and style fields. Your app's theme,
stylesheet, FluentProvider and UI-specific custom form controls remain part of its UI setup.
Use your registry components
Pass an optional adapter when creating the manager. Choose the helper matching your components' underlying library; the helper owns the native lifecycle integration. There is no runtime inspection of component names or DOM markers.
import {
createModalManager,
ModalRenderer,
radixComponents
} from "@buildkitgg/shadcn-modals-manager"
import { Button } from "@/components/ui/button"
import * as dialog from "@/components/ui/dialog"
export const modals = createModalManager({
adapter: radixComponents({ ...dialog, Button })
})
// Same renderer props and modal calls:
<ModalRenderer manager={modals} />For Base UI registry components, use baseUiComponents in place of radixComponents:
export const modals = createModalManager({
adapter: baseUiComponents({ ...dialog, Button })
})Import baseUiComponents from this package and use your Base UI dialog module. Both helpers expect Dialog,
DialogContent, DialogTitle, DialogDescription, DialogFooter and Button.
The adapter is fixed for that manager's lifetime. Omit it to use the default components. An explicit adapter takes precedence over the package default, including when using the interchangeable Fluent factory or renderer. There is no global registration or separate renderer factory. Custom components use your existing styles. Radix is supplied by your app's components; the helpers do not import it, and default consumers do not need Radix types.
Wrappers must forward the props passed by the helper, including children, accessibility attributes and lifecycle callbacks. Keep native modal behavior and normal unmounting enabled: do not force-mount a closed Radix dialog. Radix CSS exit animations finish before its close-focus callback removes the entry; Base UI uses its open-change-complete callback. Add native styling or layout customization inside your wrappers rather than to shared modal options.
API
createModalManager({ labels?, adapter? }): shared open, alert, confirm and typed modal definitions.ModalRenderer: renders the manager's adapter; mount once per manager.baseUiComponents(components)/radixComponents(components): bind the native dialog lifecycle.ModalManager,ModalManagerOptions,ModalRendererProps,ModalSurfaceOptions: shared contracts.BaseUiModalComponents,RadixModalComponents,ModalAdapter: optional integration contracts.
Keep the returned modal handle to update an open instance. Standard modals use handle.update() for opening options;
custom definitions use the same method with { data: partialState, title?, description?, dismissible?, surfaceProps? }.
Functional updaters receive the current presentation and current.data. Every component slot's controls.update()
works identically. title, body and footer accept React nodes or { component: Component }. A custom footer
replaces the helper buttons, leaving variants and styling to your components. Use ariaLabel when the title has no
accessible text. The updateable onClose({ id, result, reason }) callback observes settlement once.
See update examples, lifecycle and architecture, typed forms and package guide.
Component style
Install @buildkitgg/shadcn-baseui-kit or alias a generated style under that name. The manager uses the app's peer
implementation and stylesheet. Style selection needs no renderer adapter.
Localization and Tailwind
Default labels follow the selected kit’s ShadcnLocalizationProvider; explicit labels take precedence. See
localization. For apps using the kit’s tailwind.css source entry, omit this
manager’s stylesheet because it imports compiled kit utilities. The manager uses the component styles generated by your
app.
