The ViewModal component composes a View inside a centered Modal. It combines the layout/header conveniences of View with Modal’s overlayed presentation (using Dialog/Radix UI under the hood). Defaults can be provided via UIProvider/ui.config.ts.
import React from "react";
import {ViewModal, Button, ModalRadius, ModalAnimation} from "addon-ui";
export function Example() {
const [open, setOpen] = React.useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open profile</Button>
<ViewModal
open={open}
onOpenChange={setOpen}
title="Profile"
subtitle="Manage your personal info"
before={<span>👤</span>}
radius={ModalRadius.Medium}
animation={ModalAnimation.FadeScale}
>
<div style={{padding: 16, minWidth: 320}}>
<p>Modal body content lives inside the View body.</p>
<Button onClick={() => setOpen(false)}>Close</Button>
</div>
</ViewModal>
</>
);
}Only the prop name, type, and default are listed below. ViewModal accepts all View props and most Modal props except Modal’s title (use View’s title instead).
| Prop | Type | Default |
|---|---|---|
speed |
number |
200 |
fullscreen |
boolean (applies to Modal content) |
true |
radius |
'none' | 'small' | 'medium' | 'large' |
— |
animation |
'fade' | 'fadeScale' |
'fadeScale' |
closeButton |
boolean | IconButtonProps | ReactElement |
true |
onClose |
() => void |
— |
open |
boolean |
— |
defaultOpen |
boolean |
— |
onOpenChange |
(open: boolean) => void |
— |
modal |
boolean |
— |
container |
HTMLElement |
— |
description |
string |
— |
| View header props | title, subtitle, before, after, wrapClassName, titleClassName, beforeClassName, afterClassName, subtitleClassName, alignCenter |
see View |
| View layout props | center, showSeparate, bodyClassName, headerClassName, children |
— |
className |
string (passed to Modal content) |
— |
overlayClassName |
string (Modal overlay) |
— |
childrenClassName |
string (Modal child wrapper; inner View body has its own classes) |
— |
Notes:
- Modal’s standalone
titleprop is intentionally omitted in ViewModal. Use the Viewtitleprop instead. - Defaults may also be provided globally via theme/config (
UIProvider,ui.config.ts). Local props take precedence over global config.
// Radius
ModalRadius.None;
ModalRadius.Small;
ModalRadius.Medium;
ModalRadius.Large;
// Animation
ModalAnimation.Fade;
ModalAnimation.FadeScale;ViewModal uses Modal → Dialog under the hood (Radix UI Dialog). In addition to the props above, you can use common Radix Dialog props via Modal:
- Root:
open,defaultOpen,onOpenChange,modal - Portal:
container - Content: standard event handlers like
onOpenAutoFocus,onCloseAutoFocus,onEscapeKeyDown,onPointerDownOutside
Full reference: https://www.radix-ui.com/primitives/docs/components/dialog
ViewModal doesn’t define its own stylesheet; it uses Modal and View styles. Below are only the variables actually referenced by those stylesheets, with exact fallback chains.
From src/components/Modal/modal.module.scss:
| Variable | Fallback chain |
|---|---|
--modal-overlay-bg-color |
var(--modal-overlay-bg-color, var(--dialog-overlay-bg-color, #111)) |
--modal-width |
var(--modal-width, 90vw) |
--modal-max-width |
var(--modal-max-width, 350px) |
--modal-max-height |
var(--modal-max-height, 85vh) |
--modal-padding |
var(--modal-padding, 0) |
--modal-border-radius |
var(--modal-border-radius, 10px) |
--modal-box-shadow |
var(--modal-box-shadow, 0 0 4px rgba(0, 0, 0, 0.5)) |
--modal-bg-color |
var(--modal-bg-color, var(--bg-primary-color)) |
--modal-border-radius-sm |
Contextual defaults: 5px (small), 15px (medium), 20px (large) |
--modal-close-offset |
var(--modal-close-offset, 5px) |
--modal-animation-content-scale |
var(--modal-animation-content-scale, 0.96) |
Notes (Modal):
- The
fullscreenmodifier forces 100% width/height and resets border-radius by class, not by variable. - The overlay color falls back to Dialog’s overlay.
- Animation choice is prop-driven; duration comes from Dialog’s
speedprop (inline style).
From src/components/View/view.module.scss:
| Variable | Fallback chain |
|---|---|
--view-header-padding-bottom |
var(--view-header-padding-bottom, var(--header-padding, var(--side-padding-sm))) |
--view-header-title-color |
var(--view-header-title-color, var(--text-primary-color)) |
--view-header-title-font-family |
var(--view-header-title-font-family, var(--font-family)), sans-serif |
--view-header-separate-width |
var(--view-header-separate-width, 1px) |
--view-header-separate-color |
var(--view-header-separate-color, var(--separator-color)) |
Provide defaults via theme/config for both the modal behavior and the embedded view header:
// ui.config.ts
import {defineConfig} from "addon-ui/config";
import {ModalRadius, ModalAnimation} from "addon-ui";
export default defineConfig({
components: {
viewModal: {
radius: ModalRadius.Medium,
animation: ModalAnimation.FadeScale,
fullscreen: true,
// View defaults
alignCenter: true,
showSeparate: true,
},
},
});Or at runtime with the provider:
import {UIProvider} from "addon-ui";
<UIProvider
components={{
viewModal: {
radius: "small",
animation: "fade",
fullscreen: false,
alignCenter: false,
showSeparate: false,
},
}}
>
{/* ... */}
</UIProvider>;- Semantics and focus management are provided by Radix Dialog via Modal. While open, focus is trapped and background content is inert (when
modalis true). - Provide meaningful
titleand optionalsubtitlevia View props; they are rendered semantically in the header and assist screen reader users. - Ensure close actions inside the modal are keyboard accessible; Esc key behavior can be managed via Dialog props.