Overlays

Modal

Adaptive overlay that renders as a bottom sheet on mobile and a centered dialog on desktop.

Adaptive Modal

Modals provide a focused overlay for critical tasks. They automatically adapt to the platform: a centered dialog on desktop and a draggable bottom sheet on mobile.

'use client'

import React, { useState } from 'react'
import { Button, Modal, Stack, Input } from 'biibaos'

export default function ProfileModal() {
  const [open, setOpen] = useState(false)

  return (
    <>
      <Button variant="primary" onClick={() => setOpen(true)}>
        Edit Profile
      </Button>

      <Modal 
        isOpen={open} 
        onClose={() => setOpen(false)}
        title="Edit Profile"
        description="Update your personal information."
        footer={(
          <Stack gap={12} justify="end" fullWidth>
            <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
            <Button onClick={() => setOpen(false)}>Save Changes</Button>
          </Stack>
        )}
      >
        <Stack direction="column" gap={16}>
          <Input label="Display Name" defaultValue="John Doe" />
          <Input label="Email" defaultValue="john@example.com" />
        </Stack>
      </Modal>
    </>
  )
}

Sizing

Control the width on desktop to suit your content, from narrow alerts to wide data editors.

'use client'

import React, { useState } from 'react'
import { Button, Modal, Stack, View, Text } from 'biibaos'

export default function ModalSizing() {
  const [activeModal, setActiveModal] = useState<string | null>(null)

  return (
    <Stack gap={12}>
      <Button variant="secondary" onClick={() => setActiveModal('small')}>Small (400px)</Button>
      <Button variant="secondary" onClick={() => setActiveModal('medium')}>Medium (600px)</Button>
      <Button variant="secondary" onClick={() => setActiveModal('large')}>Large (900px)</Button>

      <Modal 
        isOpen={activeModal === 'small'} 
        onClose={() => setActiveModal(null)} 
        title="Small Modal"
        maxWidth={400}
      >
        <View p={24}>
          <Text color="muted">Modal content goes here (400px wide).</Text>
        </View>
      </Modal>

      <Modal 
        isOpen={activeModal === 'medium'} 
        onClose={() => setActiveModal(null)} 
        title="Medium Modal"
        maxWidth={600}
      >
        <View p={24}>
          <Text color="muted">Modal content goes here (600px wide).</Text>
        </View>
      </Modal>

      <Modal 
        isOpen={activeModal === 'large'} 
        onClose={() => setActiveModal(null)} 
        title="Large Modal"
        maxWidth={900}
      >
        <View p={24}>
          <Text color="muted">Modal content goes here (900px wide).</Text>
        </View>
      </Modal>
    </Stack>
  )
}

Properties

PropTypeDefaultDescription
isOpenbooleanControlled state of overlay visibility
onClose() => voidCallback function triggered when closing the overlay
childrenReact.ReactNodeMain descriptive text or overlay children layout
titlestringTitle shown at the top of the modal
descriptionstringDescription text rendered below the title
headerActionsReact.ReactNodeContent rendered in the top-right corner — e.g. a close button
footerReact.ReactNodeContent at the bottom — e.g. action buttons
maxWidthnumber | string520Max width of the dialog on desktop
closeOnBackdropbooleantruePrevent closing when the backdrop is clicked
closeOnEscapebooleantruePrevent closing via Escape key
noBackdropbooleanfalseRender without a backdrop
centeredbooleanfalseCenter children vertically
portalTargetHTMLElement | nullPortal target — defaults to document.body
zIndexnumber1000z-index override
maxHeightnumber | stringMax height of the modal body