CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-mantine--core

React components library focused on usability, accessibility and developer experience

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

overlay-components.mddocs/

Overlay Components

@mantine/core provides comprehensive overlay components for creating modal dialogs, popovers, tooltips, and other floating elements. These components handle complex positioning, focus management, and accessibility requirements.

Modal

Full-featured modal dialog component with backdrop, transitions, and accessibility.

interface ModalProps {
  /** If true, modal is opened */
  opened: boolean;
  /** Called when modal should be closed */
  onClose: () => void;
  /** Modal title */
  title?: React.ReactNode;
  /** Modal content */
  children?: React.ReactNode;
  /** Modal size */
  size?: MantineSize | string | number;
  /** If true, modal will be centered */
  centered?: boolean;
  /** If true, modal cannot be closed by clicking outside or pressing Escape */
  closeOnClickOutside?: boolean;
  /** If true, modal cannot be closed by pressing Escape */
  closeOnEscape?: boolean;
  /** If true, close button will not be rendered */
  withCloseButton?: boolean;
  /** Modal z-index */
  zIndex?: number;
  /** Overlay props */
  overlayProps?: OverlayProps;
  /** Transition props */
  transitionProps?: TransitionProps;
  /** Modal radius */
  radius?: MantineRadius;
  /** If true, modal will have full screen on mobile */
  fullScreen?: boolean;
  /** Modal keep mounted */
  keepMounted?: boolean;
}

interface ModalRootProps {
  /** Root children */
  children: React.ReactNode;
  /** If true, modal is opened */
  opened: boolean;
  /** Called when modal should be closed */
  onClose: () => void;
  /** Modal z-index */
  zIndex?: number;
  /** If true, modal cannot be closed by clicking outside */
  closeOnClickOutside?: boolean;
  /** If true, modal cannot be closed by pressing Escape */
  closeOnEscape?: boolean;
  /** If true, modal will be centered */
  centered?: boolean;
  /** Transition props */
  transitionProps?: TransitionProps;
  /** If true, modal will have full screen on mobile */
  fullScreen?: boolean;
}

interface ModalOverlayProps {
  /** Overlay background color */
  color?: string;
  /** Overlay background opacity */
  backgroundOpacity?: number;
  /** Overlay blur */
  blur?: number;
}

interface ModalContentProps {
  /** Content children */
  children: React.ReactNode;
  /** Modal size */
  size?: MantineSize | string | number;
  /** Modal radius */
  radius?: MantineRadius;
}

interface ModalHeaderProps {
  /** Header children */
  children: React.ReactNode;
}

interface ModalTitleProps {
  /** Title content */
  children: React.ReactNode;
}

interface ModalCloseButtonProps {
  /** Close button aria-label */
  'aria-label'?: string;
}

interface ModalBodyProps {
  /** Body children */
  children: React.ReactNode;
}

Usage Example:

import { Modal, Button, TextInput, Group } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function ModalDemo() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <>
      <Modal opened={opened} onClose={close} title="Authentication">
        <TextInput label="Email" placeholder="your@email.com" />
        <TextInput label="Password" type="password" mt="md" />
        <Group mt="md" justify="flex-end">
          <Button onClick={close}>Login</Button>
        </Group>
      </Modal>

      <Button onClick={open}>Open modal</Button>
    </>
  );
}

// Compound components usage
function CompoundModal() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <>
      <Modal.Root opened={opened} onClose={close}>
        <Modal.Overlay />
        <Modal.Content>
          <Modal.Header>
            <Modal.Title>Modal title</Modal.Title>
            <Modal.CloseButton />
          </Modal.Header>
          <Modal.Body>
            Modal content
          </Modal.Body>
        </Modal.Content>
      </Modal.Root>

      <Button onClick={open}>Open modal</Button>
    </>
  );
}

ModalBase

Unstyled base modal implementation for custom modal components.

interface ModalBaseProps {
  /** If true, modal is opened */
  opened: boolean;
  /** Called when modal should be closed */
  onClose: () => void;
  /** Modal content */
  children?: React.ReactNode;
  /** Modal size */
  size?: MantineSize | string | number;
  /** If true, modal will be centered */
  centered?: boolean;
  /** If true, modal cannot be closed by clicking outside */
  closeOnClickOutside?: boolean;
  /** If true, modal cannot be closed by pressing Escape */
  closeOnEscape?: boolean;
  /** Modal z-index */
  zIndex?: number;
  /** Overlay props */
  overlayProps?: OverlayProps;
  /** Transition props */
  transitionProps?: TransitionProps;
  /** If true, modal will have full screen on mobile */
  fullScreen?: boolean;
}

Drawer

Slide-out drawer component for navigation or content panels.

interface DrawerProps {
  /** If true, drawer is opened */
  opened: boolean;
  /** Called when drawer should be closed */
  onClose: () => void;
  /** Drawer title */
  title?: React.ReactNode;
  /** Drawer content */
  children?: React.ReactNode;
  /** Drawer position */
  position?: 'top' | 'bottom' | 'left' | 'right';
  /** Drawer size */
  size?: MantineSize | string | number;
  /** If true, drawer cannot be closed by clicking outside */
  closeOnClickOutside?: boolean;
  /** If true, drawer cannot be closed by pressing Escape */
  closeOnEscape?: boolean;
  /** If true, close button will not be rendered */
  withCloseButton?: boolean;
  /** Drawer z-index */
  zIndex?: number;
  /** Overlay props */
  overlayProps?: OverlayProps;
  /** Transition props */
  transitionProps?: TransitionProps;
  /** If true, drawer will have scroll area */
  scrollAreaComponent?: any;
}

interface DrawerRootProps extends Pick<DrawerProps, 'opened' | 'onClose' | 'position' | 'size' | 'closeOnClickOutside' | 'closeOnEscape' | 'zIndex' | 'transitionProps'> {
  /** Root children */
  children: React.ReactNode;
}

interface DrawerOverlayProps extends ModalOverlayProps {}

interface DrawerContentProps {
  /** Content children */
  children: React.ReactNode;
}

interface DrawerHeaderProps {
  /** Header children */
  children: React.ReactNode;
}

interface DrawerTitleProps {
  /** Title content */
  children: React.ReactNode;
}

interface DrawerCloseButtonProps {
  /** Close button aria-label */
  'aria-label'?: string;
}

interface DrawerBodyProps {
  /** Body children */
  children: React.ReactNode;
}

Usage Example:

import { Drawer, Button, Group } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function DrawerDemo() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <>
      <Drawer opened={opened} onClose={close} title="Authentication">
        <p>Drawer content...</p>
        <Group mt="xl">
          <Button variant="outline" onClick={close}>
            Cancel
          </Button>
          <Button onClick={close}>
            Save
          </Button>
        </Group>
      </Drawer>

      <Button onClick={open}>Open Drawer</Button>
    </>
  );
}

// Different positions
function DrawerPositions() {
  return (
    <>
      <Drawer position="left" opened={opened} onClose={close}>
        Left drawer
      </Drawer>
      <Drawer position="right" opened={opened} onClose={close}>
        Right drawer
      </Drawer>
      <Drawer position="top" opened={opened} onClose={close}>
        Top drawer
      </Drawer>
      <Drawer position="bottom" opened={opened} onClose={close}>
        Bottom drawer
      </Drawer>
    </>
  );
}

Popover

Floating popover component with positioning and trigger options.

interface PopoverProps {
  /** Popover content */
  children: React.ReactNode;
  /** If true, popover is opened */
  opened?: boolean;
  /** Default opened state */
  defaultOpened?: boolean;
  /** Called when popover state changes */
  onChange?: (opened: boolean) => void;
  /** Popover position relative to target */
  position?: FloatingPosition;
  /** Popover placement offset */
  offset?: number;
  /** If true, popover will be closed on outside click */
  closeOnClickOutside?: boolean;
  /** If true, popover will be closed on escape key press */
  closeOnEscape?: boolean;
  /** If true, popover will be closed when target element is clicked */
  clickOutsideEvents?: string[];
  /** Popover width */
  width?: number | 'target';
  /** If true, popover will have arrow */
  withArrow?: boolean;
  /** Arrow size */
  arrowSize?: number;
  /** Arrow position */
  arrowPosition?: 'center' | 'side';
  /** Arrow offset */
  arrowOffset?: number;
  /** If true, popover will be disabled */
  disabled?: boolean;
  /** Popover z-index */
  zIndex?: number;
  /** Popover radius */
  radius?: MantineRadius;
  /** Popover shadow */
  shadow?: MantineShadow;
  /** If true, popover will have focus trap */
  trapFocus?: boolean;
  /** If true, popover will return focus to trigger when closed */
  returnFocus?: boolean;
}

interface PopoverTargetProps {
  /** Target element */
  children: React.ReactElement;
  /** Popover reference type */
  refProp?: string;
}

interface PopoverDropdownProps {
  /** Dropdown content */
  children: React.ReactNode;
}

Usage Example:

import { Popover, Button, Text } from '@mantine/core';

function PopoverDemo() {
  return (
    <Popover width={200} position="bottom" withArrow shadow="md">
      <Popover.Target>
        <Button>Toggle popover</Button>
      </Popover.Target>
      <Popover.Dropdown>
        <Text size="sm">This is uncontrolled popover</Text>
      </Popover.Dropdown>
    </Popover>
  );
}

// Controlled popover
function ControlledPopover() {
  const [opened, setOpened] = useState(false);

  return (
    <Popover opened={opened} onChange={setOpened}>
      <Popover.Target>
        <Button onClick={() => setOpened((o) => !o)}>
          Toggle popover
        </Button>
      </Popover.Target>
      <Popover.Dropdown>
        <Text size="sm">Controlled popover content</Text>
      </Popover.Dropdown>
    </Popover>
  );
}

HoverCard

Popover that opens on hover with delay support.

interface HoverCardProps extends Omit<PopoverProps, 'opened' | 'onChange'> {
  /** Open delay in ms */
  openDelay?: number;
  /** Close delay in ms */
  closeDelay?: number;
  /** Called when hover card opens */
  onOpen?: () => void;
  /** Called when hover card closes */
  onClose?: () => void;
}

interface HoverCardTargetProps {
  /** Target element */
  children: React.ReactElement;
}

interface HoverCardDropdownProps {
  /** Dropdown content */
  children: React.ReactNode;
}

Usage Example:

import { HoverCard, Button, Text, Avatar, Group } from '@mantine/core';

function HoverCardDemo() {
  return (
    <Group justify="center">
      <HoverCard width={280} shadow="md">
        <HoverCard.Target>
          <Avatar
            src="https://images.unsplash.com/photo-1623582854588-d60de57fa33f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80"
            radius="xl"
          />
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <div>
            <Avatar
              src="https://images.unsplash.com/photo-1623582854588-d60de57fa33f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80"
              size={94}
              radius="md"
            />
            <Text fz="sm" tt="uppercase" fw={700} c="dimmed">
              Software engineer
            </Text>

            <Text fz="lg" fw={500} mt={-5}>
              Jane Doe
            </Text>

            <Text fz="sm" c="dimmed">
              Jane.Doe@email.com • +47 333 22 11
            </Text>
          </div>
        </HoverCard.Dropdown>
      </HoverCard>
    </Group>
  );
}

Tooltip

Simple tooltip component for providing additional information on hover.

interface TooltipProps {
  /** Tooltip label */
  label: React.ReactNode;
  /** Tooltip children (trigger element) */
  children: React.ReactNode;
  /** Tooltip position */
  position?: FloatingPosition;
  /** If true, tooltip will be disabled */
  disabled?: boolean;
  /** Tooltip offset from target */
  offset?: number;
  /** Tooltip z-index */
  zIndex?: number;
  /** Tooltip radius */
  radius?: MantineRadius;
  /** Tooltip color */
  color?: MantineColor;
  /** If true, tooltip will have arrow */
  withArrow?: boolean;
  /** Arrow size */
  arrowSize?: number;
  /** Arrow position */
  arrowPosition?: 'center' | 'side';
  /** Arrow offset */
  arrowOffset?: number;
  /** Open delay in ms */
  openDelay?: number;
  /** Close delay in ms */
  closeDelay?: number;
  /** If true, tooltip will stay open when hovered */
  keepMounted?: boolean;
  /** Events that trigger tooltip */
  events?: { hover: boolean; focus: boolean; touch: boolean };
}

interface TooltipFloatingProps extends TooltipProps {}

interface TooltipGroupProps {
  /** Group children */
  children: React.ReactNode;
  /** Open delay for all tooltips in group */
  openDelay?: number;
  /** Close delay for all tooltips in group */
  closeDelay?: number;
}

Usage Example:

import { Tooltip, Button, Group } from '@mantine/core';

function TooltipDemo() {
  return (
    <Group>
      <Tooltip label="This is tooltip">
        <Button variant="outline">Button with tooltip</Button>
      </Tooltip>

      <Tooltip label="Colored tooltip" color="orange">
        <Button variant="outline">Orange tooltip</Button>
      </Tooltip>

      <Tooltip
        label="Tooltip with arrow"
        withArrow
        position="bottom"
      >
        <Button variant="outline">With arrow</Button>
      </Tooltip>
    </Group>
  );
}

// Tooltip group
function TooltipGroupDemo() {
  return (
    <Tooltip.Group openDelay={500} closeDelay={100}>
      <Group>
        <Tooltip label="Tooltip 1">
          <Button variant="outline">Button 1</Button>
        </Tooltip>
        <Tooltip label="Tooltip 2">
          <Button variant="outline">Button 2</Button>
        </Tooltip>
        <Tooltip label="Tooltip 3">
          <Button variant="outline">Button 3</Button>
        </Tooltip>
      </Group>
    </Tooltip.Group>
  );
}

Menu

Context menu component with items, labels, and dividers.

interface MenuProps {
  /** Menu content */
  children: React.ReactNode;
  /** If true, menu is opened */
  opened?: boolean;
  /** Default opened state */
  defaultOpened?: boolean;
  /** Called when menu state changes */
  onChange?: (opened: boolean) => void;
  /** Menu position */
  position?: FloatingPosition;
  /** Menu offset */
  offset?: number;
  /** Menu trigger */
  trigger?: 'click' | 'hover';
  /** Open delay for hover trigger */
  openDelay?: number;
  /** Close delay for hover trigger */
  closeDelay?: number;
  /** If true, menu will be closed on item click */
  closeOnItemClick?: boolean;
  /** If true, menu will be closed on outside click */
  closeOnClickOutside?: boolean;
  /** If true, menu will be closed on escape */
  closeOnEscape?: boolean;
  /** Menu width */
  width?: number | 'target';
  /** If true, menu will have arrow */
  withArrow?: boolean;
  /** Arrow size */
  arrowSize?: number;
  /** Arrow position */
  arrowPosition?: 'center' | 'side';
  /** Arrow offset */
  arrowOffset?: number;
  /** Menu z-index */
  zIndex?: number;
  /** Menu radius */
  radius?: MantineRadius;
  /** Menu shadow */
  shadow?: MantineShadow;
  /** If true, menu will have focus trap */
  trapFocus?: boolean;
  /** If true, menu will return focus to trigger */
  returnFocus?: boolean;
  /** Keyboard events */
  loop?: boolean;
}

interface MenuTargetProps {
  /** Target element */
  children: React.ReactElement;
}

interface MenuDropdownProps {
  /** Dropdown content */
  children: React.ReactNode;
}

interface MenuItemProps {
  /** Item content */
  children: React.ReactNode;
  /** Item left section */
  leftSection?: React.ReactNode;
  /** Item right section */
  rightSection?: React.ReactNode;
  /** Item color when hovered/focused */
  color?: MantineColor;
  /** If true, item is disabled */
  disabled?: boolean;
  /** Called when item is clicked */
  onClick?: () => void;
}

interface MenuLabelProps {
  /** Label content */
  children: React.ReactNode;
}

interface MenuDividerProps {
  /** Divider label */
  label?: React.ReactNode;
}

Usage Example:

import { Menu, Button, Text, rem } from '@mantine/core';

function MenuDemo() {
  return (
    <Menu>
      <Menu.Target>
        <Button>Toggle menu</Button>
      </Menu.Target>

      <Menu.Dropdown>
        <Menu.Label>Application</Menu.Label>
        <Menu.Item leftSection="⚙️">
          Settings
        </Menu.Item>
        <Menu.Item leftSection="💬">
          Messages
        </Menu.Item>
        <Menu.Item leftSection="📷">
          Gallery
        </Menu.Item>

        <Menu.Divider />

        <Menu.Label>Danger zone</Menu.Label>
        <Menu.Item leftSection="🗃️">
          Transfer my data
        </Menu.Item>
        <Menu.Item
          color="red"
          leftSection="🗑️"
        >
          Delete my account
        </Menu.Item>
      </Menu.Dropdown>
    </Menu>
  );
}

Dialog

Simple dialog component for notifications and confirmations.

interface DialogProps {
  /** If true, dialog is opened */
  opened: boolean;
  /** Called when dialog should be closed */
  onClose?: () => void;
  /** Dialog content */
  children: React.ReactNode;
  /** Dialog position */
  position?: { top?: number; bottom?: number; left?: number; right?: number };
  /** Dialog size */
  size?: MantineSize | number;
  /** Dialog radius */
  radius?: MantineRadius;
  /** Dialog shadow */
  shadow?: MantineShadow;
  /** Dialog z-index */
  zIndex?: number;
  /** If true, dialog will have close button */
  withCloseButton?: boolean;
  /** If true, dialog cannot be closed by clicking outside */
  closeOnClickOutside?: boolean;
  /** If true, dialog cannot be closed by pressing Escape */
  closeOnEscape?: boolean;
  /** Transition props */
  transitionProps?: TransitionProps;
}

Usage Example:

import { Dialog, Text, Button, Group } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function DialogDemo() {
  const [opened, { toggle, close }] = useDisclosure(false);

  return (
    <>
      <Group justify="center">
        <Button onClick={toggle}>Toggle dialog</Button>
      </Group>

      <Dialog
        opened={opened}
        withCloseButton
        onClose={close}
        size="lg"
        radius="md"
      >
        <Text size="sm" mb="xs" fw={500}>
          Subscribe to email newsletter
        </Text>

        <Text size="xs">
          Subscribe to our newsletter to stay up to date with the latest news
        </Text>
      </Dialog>
    </>
  );
}

Overlay

Generic overlay component for creating backgrounds.

interface OverlayProps {
  /** Overlay background color */
  color?: string;
  /** Overlay opacity */
  backgroundOpacity?: number;
  /** Overlay blur amount */
  blur?: number;
  /** Overlay z-index */
  zIndex?: number;
  /** Overlay radius */
  radius?: MantineRadius;
  /** If true, overlay will cover entire viewport */
  fixed?: boolean;
  /** Overlay children */
  children?: React.ReactNode;
  /** Called when overlay is clicked */
  onClick?: () => void;
}

Usage Example:

import { Overlay, Button, Box } from '@mantine/core';
import { useState } from 'react';

function OverlayDemo() {
  const [visible, setVisible] = useState(false);

  return (
    <Box pos="relative" h={200}>
      {visible && <Overlay color="#000" backgroundOpacity={0.35} />}
      <Button onClick={() => setVisible(!visible)}>
        Toggle overlay
      </Button>
    </Box>
  );
}

Portal

Renders children in a different part of the DOM.

interface PortalProps {
  /** Portal children */
  children: React.ReactNode;
  /** Element where portal should be rendered */
  target?: HTMLElement | string;
}

Usage Example:

import { Portal, Box, Button } from '@mantine/core';
import { useState } from 'react';

function PortalDemo() {
  const [opened, setOpened] = useState(false);

  return (
    <Box>
      <Button onClick={() => setOpened(!opened)}>
        Toggle portal
      </Button>
      
      {opened && (
        <Portal>
          <Box
            style={{
              position: 'absolute',
              top: 0,
              right: 0,
              width: 200,
              height: 100,
              backgroundColor: 'red',
              zIndex: 1000,
            }}
          >
            Portal content rendered at document.body
          </Box>
        </Portal>
      )}
    </Box>
  );
}

Affix

Fixed positioned element that sticks to viewport edge.

interface AffixProps {
  /** Affix position */
  position?: { top?: number; bottom?: number; left?: number; right?: number };
  /** Affix z-index */
  zIndex?: number;
  /** If true, affix will be within scrollable container */
  withinPortal?: boolean;
  /** Affix children */
  children: React.ReactNode;
  /** Target element for within portal */
  portalProps?: PortalProps;
}

Usage Example:

import { Affix, Button, Text, Transition } from '@mantine/core';
import { useWindowScroll } from '@mantine/hooks';

function AffixDemo() {
  const [scroll, scrollTo] = useWindowScroll();

  return (
    <>
      <Text ta="center">Scroll down to see button</Text>
      
      <Affix position={{ bottom: 20, right: 20 }}>
        <Transition transition="slide-up" mounted={scroll.y > 0}>
          {(transitionStyles) => (
            <Button
              leftSection="↑"
              style={transitionStyles}
              onClick={() => scrollTo({ y: 0 })}
            >
              Scroll to top
            </Button>
          )}
        </Transition>
      </Affix>
    </>
  );
}

FloatingIndicator

Animated indicator that moves between elements.

interface FloatingIndicatorProps {
  /** Target element selector or ref */
  target: string | HTMLElement;
  /** Parent element selector or ref */
  parent?: string | HTMLElement;
  /** Indicator className */
  className?: string;
  /** If true, indicator will be disabled */
  disabled?: boolean;
}

Usage Example:

import { FloatingIndicator, UnstyledButton } from '@mantine/core';
import { useState } from 'react';

function FloatingIndicatorDemo() {
  const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
  const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({});
  const [active, setActive] = useState(0);

  const setControlRef = (index: number) => (node: HTMLButtonElement) => {
    controlsRefs[index] = node;
    setControlsRefs(controlsRefs);
  };

  const controls = Array(3).fill(0).map((_, index) => (
    <UnstyledButton
      key={index}
      ref={setControlRef(index)}
      onClick={() => setActive(index)}
      mod={{ active: active === index }}
    >
      Tab {index + 1}
    </UnstyledButton>
  ));

  return (
    <div ref={setRootRef}>
      <FloatingIndicator
        target={controlsRefs[active]}
        parent={rootRef}
        className="indicator"
      />
      {controls}
    </div>
  );
}

Theme Integration

Overlay components integrate with the Mantine theme system:

import { MantineProvider } from '@mantine/core';

const theme = {
  components: {
    Modal: {
      defaultProps: {
        centered: true,
        radius: 'md',
        overlayProps: { backgroundOpacity: 0.55, blur: 3 },
      },
    },
    Popover: {
      defaultProps: {
        position: 'bottom',
        withArrow: true,
        shadow: 'md',
      },
    },
    Tooltip: {
      defaultProps: {
        withArrow: true,
        color: 'dark',
      },
    },
  },
};

Accessibility Features

Overlay components include comprehensive accessibility support:

  • Focus Management: Proper focus trapping and restoration
  • Keyboard Navigation: Full keyboard support with arrow keys and Enter/Escape
  • ARIA Attributes: Proper labeling and roles for screen readers
  • Screen Reader Support: Announcements for state changes
  • Color Contrast: Sufficient contrast ratios for overlays and content

docs

button-typography-components.md

core-components.md

data-display-components.md

feedback-components.md

form-components.md

index.md

layout-components.md

navigation-components.md

overlay-components.md

theme-system.md

tile.json