npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@leafygreen-ui/drawer

v5.2.3

Published

LeafyGreen UI Kit Drawer

Readme

Drawer

npm (scoped)

View on MongoDB.design

Installation

PNPM

pnpm add @leafygreen-ui/drawer

Yarn

yarn add @leafygreen-ui/drawer

NPM

npm install @leafygreen-ui/drawer

Example

With Toolbar (Recommended)

import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import {
  DrawerLayout,
  DrawerLayoutProps,
  useDrawerToolbarContext,
  DisplayMode,
  Size,
} from '@leafygreen-ui/drawer';

// Note: DrawerContent is a placeholder for your drawer content component
// This could be any React component to render inside the drawer
const DrawerContent = () => <div>Content inside the drawer</div>;

const DRAWER_TOOLBAR_DATA: DrawerLayoutProps['toolbarData'] = [
  {
    id: 'Code',
    label: 'Code',
    content: <DrawerContent />,
    title: 'Code Title',
    glyph: 'Code',
    onClick: () => {
      console.log('Code clicked');
    },
  },
  {
    id: 'Dashboard',
    label: 'Dashboard',
    content: <DrawerContent />,
    title: 'Dashboard Title',
    glyph: 'Dashboard',
    onClick: () => {
      console.log('Dashboard clicked');
    },
  },
  {
    id: 'Plus',
    label: "Perform some action, doesn't open a drawer",
    glyph: 'Plus',
    onClick: () => {
      console.log('Plus clicked, does not update drawer');
    },
  },
  {
    id: 'Settings',
    label: 'Settings',
    content: <DrawerContent />,
    title: 'Settings Title',
    glyph: 'Settings',
    visible: false, // This item will be hidden
  },
];

const App = () => {
  const Main = () => {
    const { openDrawer, closeDrawer } = useDrawerToolbarContext();

    return (
      <main>
        <Button onClick={() => openDrawer('Code')}>Open Code Drawer</Button>
        <div>Your main application content goes here</div>
        <Button onClick={() => closeDrawer()}>Close Drawer</Button>
      </main>
    );
  };

  return (
    <div>
      <DrawerLayout
        toolbarData={DRAWER_TOOLBAR_DATA}
        displayMode={DisplayMode.Overlay}
        size={Size.Default}
        onClose={() => {}}
      >
        <Main />
      </DrawerLayout>
    </div>
  );
};

Without Toolbar

import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import { DisplayMode, Drawer, DrawerLayout } from '@leafygreen-ui/drawer';

function App() {
  const [open, setOpen] = useState(false);

  return (
    <DrawerLayout
      displayMode={DisplayMode.Embedded}
      isDrawerOpen={open}
      drawer={<Drawer title="Drawer Title">Drawer content</Drawer>}
      onClose={() => setOpen(false)}
    >
      <main>
        <Button onClick={() => setOpen(prevOpen => !prevOpen)}>
          Open Drawer
        </Button>
      </main>
    </DrawerLayout>
  );
}

DrawerLayout

DrawerLayout is a flexible layout wrapper that shifts the page content appropriately when a Drawer opens. It can be used in both overlay and embedded modes, with or without a toolbar.

With Toolbar

To use with a Toolbar, pass the toolbarData prop to render the Toolbar items and the Drawer content. Each object in the array defines a Toolbar item. If a Toolbar item is intended to perform an action other than opening a Drawer (for example, opening a modal), leave the content and title fields empty.

The Drawer and Toolbar component will be rendered automatically based on the toolbarData provided.

Toolbar Visibility

Individual toolbar items can be controlled using the visible prop. When all toolbar items have visible set to false, the entire toolbar will be automatically hidden from view. This allows for dynamic toolbar management based on application state or user permissions.

useDrawerToolbarContext()

To control the Drawer state, use the useDrawerToolbarContext hook from within <DrawerLayout>. This hook provides the openDrawer() and closeDrawer() functions to open and close the drawer programmatically. The hook takes no arguments and returns the following functions:

| Name | Signature | Description | | ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | openDrawer | (id: string) => void | Opens the Drawer associated with the Toolbar item that has the matching id in toolbarData. | | closeDrawer | () => void | Closes the Drawer. | | toggleDrawer | (id: string) => void | If clicking the currently active Toolbar item, it closes the Drawer. Otherwise, it open the Drawer with the new content. |

Rendering

import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import {
  DrawerLayout,
  DrawerLayoutProps,
  useDrawerToolbarContext,
} from '@leafygreen-ui/drawer';

// Data passed to <DrawerLayout /> to render the toolbar items and drawer content
const DRAWER_TOOLBAR_DATA: DrawerLayoutProps['toolbarData'] = [
  {
    id: 'Code',
    label: 'Code',
    content: <DrawerContent />,
    title: 'Code Title',
    glyph: 'Code',
    onClick: () => {
      console.log('Code clicked');
    },
  },
  {
    id: 'Dashboard',
    label: 'Dashboard',
    content: <DrawerContent />,
    title: 'Dashboard Title',
    glyph: 'Dashboard',
    onClick: () => {
      console.log('Dashboard clicked');
    },
  },
  {
    id: 'Plus',
    label: "Perform some action, doesn't open a drawer",
    glyph: 'Plus',
    onClick: () => {
      console.log('Plus clicked, does not update drawer');
    },
  },
];

const Component = () => {
  const Main = () => {
    const { openDrawer, closeDrawer } = useDrawerToolbarContext();

    // Content is a placeholder for your application's main content
    const Content = () => <div>Main content of your application</div>;

    return (
      <main>
        <Button onClick={() => openDrawer('Code')}>Open Code Drawer</Button>
        <Content />
        <Button onClick={() => closeDrawer()}>Close Drawer</Button>
      </main>
    );
  };

  return (
    <div>
      <DrawerLayout
        toolbarData={DRAWER_TOOLBAR_DATA}
        displayMode="embedded"
        onClose={() => {}}
      >
        <Main />
      </DrawerLayout>
    </div>
  );
};

Without Toolbar

Single Drawer instance

There are two ways to render a Drawer without a Toolbar:

  1. Pass the Drawer component to the drawer prop of <DrawerLayout>. You don't need to pass open, displayMode, or onClose props to the Drawer component, as these will be handled by the DrawerLayout. (Recommended)
import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import { DisplayMode, Drawer, DrawerLayout } from '@leafygreen-ui/drawer';

function ExampleComponent() {
  const [open, setOpen] = useState(false);

  return (
    <DrawerLayout
      displayMode={DisplayMode.Embedded}
      isDrawerOpen={open}
      drawer={<Drawer title="Drawer Title">Drawer content</Drawer>}
      onClose={() => setOpen(false)}
    >
      <main>
        <Button onClick={() => setOpen(prevOpen => !prevOpen)}>
          Open Drawer
        </Button>
      </main>
    </DrawerLayout>
  );
}
  1. Pass the Drawer component as a child of <DrawerLayout>
import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import { DisplayMode, Drawer, DrawerLayout } from '@leafygreen-ui/drawer';

function App() {
  const [open, setOpen] = useState(false);

  return (
    <DrawerLayout displayMode={DisplayMode.Overlay} isDrawerOpen={open}>
      <main>
        <Button onClick={() => setOpen(prevOpen => !prevOpen)}>
          Open Drawer
        </Button>
      </main>
      <Drawer
        displayMode={DisplayMode.Overlay}
        onClose={() => setOpen(false)}
        open={open}
        title="Drawer Title"
      >
        Drawer content goes here
      </Drawer>
    </DrawerLayout>
  );
}

Multiple overlay Drawer instances

When rendering multiple overlay Drawer instances, it is recommended to wrap the Drawer's in a <DrawerStackProvider>. The DrawerStackProvider will manage the stacking of multiple Drawer instances by providing the correct z-index.

import React, { useState } from 'react';

import Button from '@leafygreen-ui/button';
import { DisplayMode, Drawer, DrawerLayout, DrawerStackProvider } from '@leafygreen-ui/drawer';


const MultipleDrawersComponent = () => {
  const [openA, setOpenA] = useState(false);
  const [openB, setOpenB] = useState(false);
  const [openC, setOpenC] = useState(false);

  return (
    <DrawerLayout
      displayMode={DisplayMode.Overlay}
      isDrawerOpen={openA || openB || openC}
      className={css`
        height: 500px;
      `}
    >
      <DrawerStackProvider>
        <div
          className={css`
            display: flex;
            flex-direction: column;
            gap: ${spacing[400]}px;
          `}
        >
          <Button onClick={() => setOpenA(prevOpen => !prevOpen)}>
            Toggle Drawer A
          </Button>
          <Button onClick={() => setOpenB(prevOpen => !prevOpen)}>
            Toggle Drawer B
          </Button>
        </div>
        <div>
          <Drawer
            open={openA}
            onClose={() => setOpenA(false)}
            title="Drawer A"
          >
            Drawer content
          </Drawer>
          <Drawer
            open={openB}
            onClose={() => setOpenB(false)}
            title="Drawer B"
          >
            <Button onClick={() => setOpenC(prevOpen => !prevOpen)}>
              Toggle Drawer C
            </Button>
            Drawer content
          </Drawer>
          <Drawer
            open={openC}
            onClose={() => setOpenC(false)}
            title="Drawer C"
          >
            Drawer content
          </Drawer>
        </div>
      </DrawerStackProvider>
    </DrawerLayout>

Resizable Drawers

DrawerLayout supports rendering resizable embedded Drawer instances with or without a toolbar. To make an embedded Drawer resizable, pass the resizable prop to the DrawerLayout component. This allows users to adjust the width of the drawer by dragging.

import React, { useState } from 'react';
import { DrawerLayout, Drawer, DisplayMode } from '@leafygreen-ui/drawer';
import Button from '@leafygreen-ui/button';

function ResizableDrawerExample() {
  const [open, setOpen] = useState(false);

  return (
    <DrawerLayout
      displayMode={DisplayMode.Embedded}
      isDrawerOpen={open}
      resizable
      drawer={
        <Drawer title="Resizable Drawer">
          <div>
            Drawer content that can be resized by dragging the left edge
          </div>
        </Drawer>
      }
      onClose={() => setOpen(false)}
    >
      <main>
        <Button onClick={() => setOpen(prevOpen => !prevOpen)}>
          Toggle Resizable Drawer
        </Button>
      </main>
    </DrawerLayout>
  );
}

You can also use the resizable feature with a toolbar-based drawer:

<DrawerLayout
  toolbarData={DRAWER_TOOLBAR_DATA}
  displayMode={DisplayMode.Embedded}
  onClose={() => {}}
  resizable
>
  {content}
</DrawerLayout>

Props

DrawerLayout

| Prop | Type | Description | Default | | --------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | children | React.ReactNode | The content that should live to the left of the Drawer. If there is a Toolbar, the content will shift to accommodate the Toolbar. In addition, if the DisplayMode is embedded, the content will also be shifted to accommodate the opening of the Drawer. | | | displayMode (optional) | 'embedded' | 'overlay' | Options to control how the drawer element is displayed * 'embedded' will display a drawer as a <div> element that takes up the full parent container height and on the same elevation as container page content. * 'overlay' will display a drawer as a <dialog> element that takes up the full parent container height and elevated above container page content. | 'overlay' | | onClose (optional) | React.MouseEventHandler<HTMLButtonElement> | Event handler called on close button click. If provided, a close button will be rendered in the Drawer header. This is only necessary if rendering the Drawer with Toolbar. | | | toolbarData (optional) | Array<LayoutData> | The array of data that will be used to render the toolbar items and the drawer content. This is REQUIRED to render the Drawer with Toolbar. Without this prop, the Drawer and Toolbar will not render and you must manually pass the Drawer as a child. See below for LayoutData props. | | | isDrawerOpen (optional) | boolean | Whether the Drawer is open. | | | drawer (optional) | React.ReactNode | The drawer component to be rendered in the layout. This is only needed if using the Drawer without a Toolbar. If using the Drawer with a toolbar, the drawer is rendered internally. | | | size (optional) | 'default' | 'large' | The size of the Drawer. Available sizes: * 'default': 432px * 'large': 520px | 'default' | | resizable (optional) | boolean | Whether the Drawer is resizable. This is only supported with embedded drawers. | false |

LayoutData

| Prop | Type | Description | Default | | ------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | id | string | The required id of the layout. This is used to open the Drawer with openDrawer(id). | | | title (optional) | React.ReactNode | The title of the Drawer. If it is a string, it will be rendered as a <h2> element. If it is a React node, it will be rendered as is. This is not required if the Toolbar item should not open a Drawer. | | | content (optional) | React.ReactNode | The content of the Drawer. This is not required if the Toolbar item should not open a Drawer. | | | disabled (optional) | boolean | Whether the toolbar item is disabled. | false | | hasPadding (optional) | boolean | Determines whether the drawer content should have padding. When false, the content area will not have padding, allowing full-width/height content. | true | | scrollable (optional) | boolean | Determines whether the drawer content should have its own scroll container. When false, the content area will not have scroll behavior. | true | | visible (optional) | boolean | Determines if the current toolbar item is visible. If all toolbar items have visible set to false, the toolbar will not be rendered. | true | | ref (optional) | React.RefObject<HTMLButtonElement> | Optional ref to be passed to the ToolbarIconButton instance. Useful for integrating with components like GuideCue that need to position relative to the button. | null | | isTooltipEnabled (optional) | boolean | Enables the tooltip to trigger based on hover events. When false, the tooltip will not show on hover. Useful when other overlays (like GuideCue) are positioned on the button. | true |

+ Extends the following from LG Toolbar props: glyph, label, and onClick.

Drawer

| Prop | Type | Description | Default | | -------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | | children | React.ReactNode | Children that will be rendered inside the Drawer | | | displayMode (optional) | 'embedded' | 'overlay' | Options to control how the drawer element is displayed * 'embedded' will display a drawer as a <div> element that takes up the full parent container height and on the same elevation as container page content. It is recommended to wrap an embedded drawer within the DrawerLayout container * 'overlay' will display a drawer as a <dialog> element that takes up the full parent container height and elevated above container page content. It is recommended to wrap an overlay drawer within the DrawerLayout container | 'overlay' | | hasPadding (optional) | boolean | Determines whether the drawer content should have padding. When false, the content area will not have padding, allowing full-width/height content. | true | | onClose (optional) | React.MouseEventHandler<HTMLButtonElement> | Event handler called on close button click. If provided, a close button will be rendered in the Drawer header | | | open (optional) | boolean | Determines if the Drawer is open or closed | false | | scrollable (optional) | boolean | Determines whether the drawer content should have its own scroll container. When false, the content area will not have scroll behavior. | true | | size (optional) | 'default' | 'large' | The size of the Drawer. Available sizes: * 'default': 432px * 'large': 520px | 'default' | | title | React.ReactNode | Title of the Drawer. If it is a string, it will be rendered as a <h2> element. If it is a React node, it will be rendered as is. | |

Padding and Scroll Behavior

hasPadding

  • Controls whether the drawer content has internal padding.
  • When hasPadding={true} (default), padding is applied to the content area.
  • When hasPadding={false}, content spans the full width and height of the drawer.

scrollable

  • Controls whether the drawer content has its own vertical scroll container.
  • When scrollable={true} (default), content can scroll vertically within the drawer, and a shadow appears when content overflows.
  • When scrollable={false}, no scroll container is applied; content will not scroll and should be sized to fit or manage its own scrolling.

Behavior Matrix

| scrollable | hasPadding | Drawer Content Behavior | | ------------ | ------------ | -------------------------------------- | | true | true | Padded, scrollable (default) | | true | false | No padding, scrollable | | false | true | Padded, not scrollable | | false | false | No padding, not scrollable (full area) |

Height Considerations

If rendering DrawerLayout inside another element, make sure that element has an explicit height. Otherwise, the layout may not size itself correctly.

Title Considerations

The title prop of the Drawer and Toolbar items can be a string or a React node. If it is a string, it will be rendered as a <h2> element. If it is a React node, it will be rendered as is and you are responsible for styling the title and adding the correct semantic HTML.

Example of a custom title:

import { css } from '@leafygreen-ui/emotion';
import { BaseFontSize, FontWeight } from '@leafygreen-ui/tokens';
import { Body } from '@leafygreen-ui/typography';
import CloudIcon from '@leafygreen-ui/icon/dist/Cloud';
import SparkleIcon from '@leafygreen-ui/icon/dist/Sparkle';
import IconButton from '@leafygreen-ui/icon-button';

const DrawerCustomTitle = () => {
  return (
    <div
      className={css`
        display: flex;
        justify-content: space-between;
        align-items: center;
      `}
    >
      <Body
        as="h2"
        baseFontSize={BaseFontSize.Body2}
        weight={FontWeight.SemiBold}
      >
        Custom title
      </Body>
      <div
        className={css`
          display: flex;
        `}
      >
        <IconButton
          aria-label="Descriptive label goes here"
          onClick={() => console.log('cloud click')}
        >
          <CloudIcon />
        </IconButton>
        <IconButton
          aria-label="Descriptive label goes here"
          onClick={() => console.log('sparkle click')}
        >
          <SparkleIcon />
        </IconButton>
      </div>
    </div>
  );
};

Test Harnesses

getTestUtils()

getTestUtils() is a util that allows consumers to reliably interact with LG Drawer in a product test suite. If the Drawer component cannot be found, an error will be thrown.

Usage

import { Drawer } from '@leafygreen-ui/drawer';
import { getTestUtils } from '@leafygreen-ui/drawer/testing';

const utils = getTestUtils(lgId?: string); // lgId refers to the custom `data-lgid` attribute passed to `Drawer`. It defaults to 'lg-drawer' if left empty.

Single Drawer

import { render } from '@testing-library/react';
import { Drawer, DrawerStackProvider } from '@leafygreen-ui/drawer';
import { getTestUtils } from '@leafygreen-ui/drawer/testing';

...

test('drawer', () => {
  render(
    <DrawerLayout displayMode={DisplayMode.Overlay}>
      <main>
        <Button onClick={() => setOpen(prevOpen => !prevOpen)}>
          Open Drawer
        </Button>
      </main>
      <Drawer
        displayMode={DisplayMode.Overlay}
        onClose={() => setOpen(false)}
        open={open}
        title="Drawer Title"
      >
        content
      </Drawer>
    </DrawerLayout>
  );
  const { getCloseButtonUtils, getDrawer, isOpen } = getTestUtils();

  expect(getDrawer()).toBeInTheDocument();
  expect(getCloseButtonUtils().getButton()).toBeInTheDocument();
  expect(isOpen()).toBeTruthy();
});

Multiple Drawer instances

When testing multiple Drawer instances it is recommended to add the custom data-lgid attribute to each Drawer.

import { render } from '@testing-library/react';
import { Drawer, DrawerStackProvider } from '@leafygreen-ui/drawer';
import { getTestUtils } from '@leafygreen-ui/drawer/testing';

...

test('Drawer', () => {
  render(
    <DrawerStackProvider>
      <Drawer data-lgid="lg-drawer-A" open={false} title="Drawer Title A">
        Drawer A content goes here.
      </Drawer>
      <Drawer data-lgid="lg-drawer-B" open={true} title="Drawer Title B">
        Drawer B content goes here.
      </Drawer>
    </DrawerStackProvider>,
  );

  const utilsA = getTestUtils('lg-drawer-A');
  const utilsB = getTestUtils('lg-drawer-B');

  // Drawer A
  expect(utilsA.getDrawer()).toBeInTheDocument();
  expect(utilsA.isOpen()).toBeFalsy();

  // Drawer B
  expect(utilsB.getDrawer()).toBeInTheDocument();
  expect(utilsB.isOpen()).toBeTruthy();
});

Drawer with Toolbar

import { render } from '@testing-library/react';
import { DrawerLayout, DrawerLayoutProps } from '@leafygreen-ui/drawer';
import { getTestUtils } from '@leafygreen-ui/drawer/testing';

...

const DRAWER_TOOLBAR_DATA: DrawerLayoutProps['toolbarData'] = [
  {
    id: 'Code',
    label: 'Code',
    content: <DrawerContent />,
    title: 'Code Title',
    glyph: 'Code',
    onClick: () => {
      console.log('Code clicked');
    },
  },
  {
    id: 'Dashboard',
    label: 'Dashboard',
    content: <DrawerContent />,
    title: 'Dashboard Title',
    glyph: 'Dashboard',
    onClick: () => {
      console.log('Dashboard clicked');
    },
  },
  {
    id: 'Plus',
    label: "Perform some action, doesn't open a drawer",
    glyph: 'Plus',
    onClick: () => {
      console.log('Plus clicked, does not update drawer');
    },
  },
];

test('Drawer', () => {
  render(
    <DrawerLayout toolbarData={DRAWER_TOOLBAR_DATA} displayMode="embedded">
      <Main />
    </DrawerLayout>,
  );

  const { getToolbarTestUtils } = getTestUtils();

  const { getDrawer, getToolbarIconButtonByLabel } = getToolbarTestUtils();
    const codeButton = getToolbarIconButtonByLabel('Code')?.getElement();
    const dashboardButton =
      getToolbarIconButtonByLabel('Code')?.getElement();

    await userEvent.click(codeButton);
    expect(getDrawer().textContent).toContain('Code Title');
});

Test Utils

const {
  findDrawer,
  getCloseButtonUtils,
  getDrawer,
  isOpen,
  queryDrawer,
  getToolbarTestUtils,
} = getTestUtils();

| Util | Description | Returns | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | findDrawer | Returns a promise that resolves to the drawer element. The promise is rejected if no elements match or if more than one match is found. | Promise<HTMLDialogElement> | Promise<HTMLDivElement> | | getCloseButtonUtils | Returns the button test utils for the close button | Button test utils return type | | getDrawer | Returns the drawer element and throws if no elements match or if more than one match is found. | HTMLDivElement | | isOpen | Checks the aria-hidden attribute and that the drawer element is visible based on CSS properties for display, opacity, transform, and visibility | boolean | | queryDrawer | Returns the drawer element or null if no elements match and throws if more than one match is found. | HTMLDivElement | | getToolbarTestUtils | Returns the Toolbar test utils for the Toolbar | Toolbar test utils return type |

Testing Considerations

The Drawer component uses the native HTMLDialogElement API for better accessibility and browser-native behavior. However, JSDOM (used by Jest and other test runners) does not fully support this API. You'll need to mock the show and close methods in your test setup:

beforeAll(() => {
  HTMLDialogElement.prototype.show = jest.fn(function mock(
    this: HTMLDialogElement,
  ) {
    this.open = true;
  });

  HTMLDialogElement.prototype.close = jest.fn(function mock(
    this: HTMLDialogElement,
  ) {
    this.open = false;
  });
});

This mock can be placed in a beforeAll block in your test file, or in a global test setup file.