vwf .

Developer Docs

Quick reference guides with props tables, usage examples, and best practices for rapid development

Modal

Flexible modal dialog with glass morphism and keyboard support

Modal

A flexible modal dialog with glass morphism effects, smooth animations, and keyboard navigation. Perfect for forms, confirmations, and displaying detailed content without leaving the current page.

🔧 Props

Modal component configuration options.

PropTypeDefaultDescription
idstring'modal'Unique identifier for the modal
titlestringundefinedModal title (optional, for aria-labelledby)
closeFunctionFunctionundefinedFunction to call when modal should close
closeOnBackdropbooleantrueWhether clicking backdrop closes modal
classstring'max-w-lg'CSS classes for modal card (auto-adds max-w-lg if no max-w-* provided)
containerClassstring''CSS classes for backdrop container

💻 Basic Usage

Simple modal with default size (max-w-lg) and behavior.

const showModal = van.state(false);

// Render button
Button({
  onclick: () => showModal.val = true
}, 'Open Modal')

// Render modal conditionally
() => showModal.val ? Modal({
  closeFunction: () => showModal.val = false
},
  div({ class: 'p-6' },
    h2({ class: 'text-xl font-semibold mb-4' }, 'Modal Title'),
    p({ class: 'text-smoke mb-4 ' + tClose }, 'Modal content goes here.'),
    Button({
      onclick: () => showModal.val = false
    }, 'Close')
  )
) : ''

📐 Size Variants

Control modal width using Tailwind max-w-* utilities.

(max-w-sm)

(max-w-md)

(max-w-lg - default)

(max-w-xl)

(max-w-2xl)

// Small modal
Modal({
  class: 'max-w-sm',
  closeFunction: closeHandler
}, content)

// Medium modal
Modal({
  class: 'max-w-md',
  closeFunction: closeHandler
}, content)

// Default (large) - auto-applied
Modal({ closeFunction: closeHandler }, content)  // Gets max-w-lg

// Extra large modal
Modal({
  class: 'max-w-2xl',
  closeFunction: closeHandler
}, content)

// Full width (with explicit max)
Modal({
  class: 'w-[90vw] max-w-4xl',
  closeFunction: closeHandler
}, content)

📑 Form Modal

Modal containing a form with validation and submit handling.

const showFormModal = van.state(false);
const userName = van.state('');
const userEmail = van.state('');

// Form modal
() => showFormModal.val ? Modal({
  title: 'Edit Profile',
  closeFunction: () => showFormModal.val = false,
  class: 'max-w-md'
},
  div({ class: 'p-6' },
    h3({ class: 'text-lg font-semibold mb-4' }, 'Edit Profile'),
    form({
      class: 'space-y-4',
      onsubmit: (e) => {
        e.preventDefault();
        // Handle submit
        showFormModal.val = false;
      }
    },
      Input({
        label: 'Name',
        value: userName,
        placeholder: 'Enter your name',
        oninput: e => userName.val = e.target.value
      }),
      Input({
        label: 'Email',
        value: userEmail,
        type: 'email',
        placeholder: 'Enter your email',
        oninput: e => userEmail.val = e.target.value
      }),
      div({ class: 'flex gap-3 pt-2' },
        Button({ type: 'submit', class: 'vwfcolor-sky' }, 'Save'),
        Button({
          type: 'button',
          class: 'outerline',
          onclick: () => showFormModal.val = false
        }, 'Cancel')
      )
    )
  )
) : ''

🔒 Disable Backdrop Close

Prevent closing modal by clicking outside (useful for forms with unsaved changes).

Modal({
  closeFunction: () => showModal.val = false,
  closeOnBackdrop: false  // Disable backdrop close
},
  div({ class: 'p-6' },
    h2('Important Action'),
    p('Click button or press Escape to close'),
    Button({
      onclick: () => showModal.val = false
    }, 'Confirm')
  )
)

🧭 Keyboard Navigation

Modal supports keyboard navigation for accessibility.

  • ✓Escape key - Always closes the modal (unless closeFunction not provided)
  • ✓Tab key - Cycles through focusable elements inside modal
  • ✓Backdrop is focusable (tabindex="-1") for keyboard event handling
  • ✓Prevents event propagation for Escape key
// Keyboard behavior is automatic
Modal({
  closeFunction: () => showModal.val = false
}, content)

// Escape key triggers closeFunction
// No configuration needed

⚡️ Best Practices

✓ Do This

✓Always Provide Close Function

- Include closeFunction prop to ensure users can dismiss the modal

✓Use Appropriate Sizing

- Choose max-w-* classes that fit your content (sm for simple forms, 2xl for detailed views)

✓Add Proper Padding

- Use p-6 for modal content to ensure comfortable spacing and readability

✓Include Visible Close Button

- Add an explicit close button for mobile users who may not know about backdrop/Escape key

✓Disable Backdrop Close for Forms

- Use closeOnBackdrop: false for forms with unsaved changes to prevent accidental loss

✓Use ARIA Labels

- Provide title prop for proper aria-labelledby and screen reader support

✓Keep Content Focused

- Keep modal content concise and focused on a single task or purpose

✗ Avoid This

✗Don't Nest Modals

- Avoid modal-within-modal patterns; use sequential modals or different UI patterns instead

✗Don't Make Modals Full-Screen

- Avoid full-screen modals on desktop; use a dedicated page instead

✗Don't Forget Form Submission

- Always handle form onsubmit events properly in modal forms

✗Don't Misuse for Simple Confirmations

- Use ConfirmModal component for simple yes/no confirmations instead of full Modal

✗Don't Overload with Content

- Avoid putting too much content; rely on scrolling for longer content

✗Don't Disable Keyboard Navigation

- Never prevent Escape key or Tab navigation; users expect these to work

✨ Key Features

⭑Glass Morphism Backdrop

- Beautiful glass effect with bg-black/50 and backdrop-blur for modern aesthetics

⭑Smooth Animations

- Fade-in backdrop and zoom-in modal animations for polished transitions

⭑Smart Default Sizing

- Automatic max-w-lg sizing when no max-w-* class is provided

⭑Keyboard Navigation

- Escape key closes modal, Tab key cycles through focusable elements

⭑Configurable Backdrop Close

- Optional closeOnBackdrop prop to control whether clicking outside dismisses modal

⭑Responsive Positioning

- Centered positioning with bottom-10 offset for comfortable mobile viewing

⭑Auto-Scroll for Tall Content

- Max height of 90vh with automatic scrolling for content overflow

⭑Click Propagation Prevention

- Clicks inside modal are contained to prevent unwanted backdrop dismissal

⭑ARIA Accessibility

- Built-in ARIA support with role, aria-modal, and aria-labelledby attributes

⭑Complete Customization

- FilterClassName support for full control over modal and container styling

💡 Common Use Cases

Typical scenarios where Modal component provides the best user experience.

📝Forms & Data Entry

Edit profile, create post, add item - any form that needs focus.

Modal({
  title: 'Create Post',
  class: 'max-w-lg',
  closeFunction: closeHandler
},
  div({ class: 'p-6' },
    form(/* form content */)
  )
)

🖼️Image/Media Viewer

Display full-size images, videos, or galleries.

Modal({
  class: 'max-w-4xl',
  closeFunction: () => showImage.val = false
},
  img({ src: imageUrl, class: 'w-full' })
)

📄Detailed Information

Show full product details, user profiles, or documentation.

Modal({
  title: 'Product Details',
  class: 'max-w-2xl',
  closeFunction: closeHandler
},
  div({ class: 'p-6' },
    // Detailed content with sections
  )
)

🔐Authentication

Login, signup, or password reset flows.

Modal({
  title: 'Sign In',
  class: 'max-w-md',
  closeOnBackdrop: false,
  closeFunction: closeHandler
},
  div({ class: 'p-6' },
    form(/* auth form */)
  )
)

Explore More Components

Browse other component categories