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, Stack, Text, View, Modal, Icon } from 'biibaos'
import { Check, CreditCard, Zap } from 'lucide-react'

export default function App() {
  const [open, setOpen] = useState(false)
  return (
    <>
      <Button variant="primary" onClick={() => setOpen(true)} leftIcon={<Icon icon={Zap} size={16} fill="currentColor" />}>
        Upgrade to Pro
      </Button>
      <Modal
        isOpen={open}
        onClose={() => setOpen(false)}
        title="Upgrade to Pro Workspace"
        description="Unlock advanced features and collaborate with unlimited team members."
        footer={(
          <Stack gap={12} justify="end" fullWidth>
            <Button variant="ghost" onClick={() => setOpen(false)}>Maybe Later</Button>
            <Button variant="primary" leftIcon={<Icon icon={CreditCard} size={16} />} onClick={() => setOpen(false)}>
              Upgrade for $29/mo
            </Button>
          </Stack>
        )}
      >
        <Stack direction="column" gap={20}>
          <View bg="surface-raised" p={20} radius="lg" border>
            <Stack gap={16} direction="column">
              <Stack gap={12} align="center" direction="row">
                <Stack align="center" justify="center" style={{ background: 'var(--biiba-success)', width: 24, height: 24, borderRadius: '50%' }}>
                  <Icon icon={Check} size={14} color="var(--biiba-success-fg)" />
                </Stack>
                <Text weight="medium">Unlimited Team Members</Text>
              </Stack>
              <Stack gap={12} align="center" direction="row">
                <Stack align="center" justify="center" style={{ background: 'var(--biiba-success)', width: 24, height: 24, borderRadius: '50%' }}>
                  <Icon icon={Check} size={14} color="var(--biiba-success-fg)" />
                </Stack>
                <Text weight="medium">Advanced Analytics Dashboard</Text>
              </Stack>
              <Stack gap={12} align="center" direction="row">
                <Stack align="center" justify="center" style={{ background: 'var(--biiba-success)', width: 24, height: 24, borderRadius: '50%' }}>
                  <Icon icon={Check} size={14} color="var(--biiba-success-fg)" />
                </Stack>
                <Text weight="medium">Priority 24/7 Support</Text>
              </Stack>
            </Stack>
          </View>
          <Text size="sm" color="muted">
            You will be charged immediately. You can cancel your subscription at any time from your billing settings.
          </Text>
        </Stack>
      </Modal>
    </>
  )
}

Sizing

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

'use client'

import React from 'react'
import { Stack } from 'biibaos'

export default function App() {
  return (
    <Stack gap={12}>
            <ModalTrigger label="Small (400px)" maxWidth={400} />
            <ModalTrigger label="Medium (600px)" maxWidth={600} />
            <ModalTrigger label="Large (900px)" maxWidth={900} />
          </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