Dialog

Interface of Dialog
🏗 Coming Soon

Dialogs break out of the standard application flow and UI to present new information or required actions.

Warning
Dialog provides a general purpose (empty & unstyled) overlay. Confirm will likely be more useful if your intent is to render a standard user confirmation dialog.

Standard Use

Dialog operates in a "uncontrolled" manner.

Controlled

Dialog can be used in a "controlled" manner by specifying the isOpen property. An onClose callback should also be specified so that clicking the dialog's backdrop or calling the DialogContext.closeModal method will work as expected.

Hook: useDialog

Dialog is also offered as a React Hook via useDialog. It returns the open callback and rendered dialog.

Render Props

Dialog supports render-props style use in cases where the simple compositional syntax is unable to automatically spread the dialog props down on the the child element properly.

Terminology

Dialogs are assembled of two pieces: an overlay and a surface. The Backdrop component is the semi-opaque full-screen overlay which signals that the the rest of the application is inaccessible. The Surface component sits on top of the overlay and renders the relevant content.

The most common pattern for a Dialog is the Confirm pattern.

Backdrop

This provides the backdrop behind dialogs. It can be customized via the backdrop property. These must be a CSSProperty compatible key / value paired object.

Surface

Surface provides the container that contains the content. It can be customized via the surfaceStyles property. These must be a CSSProperty compatible key / value paired object.

ReferenceError: Surface is not defined

Props: width and maxWidth

All variants of Dialog allow you to override width and max-width styles to suit your content. By default, width is unassigned so that Dialog Surface will conform to the width of its content. At the same time, maxWidth constrains the Dialog surface's width to be no larger than the specified value.

maxWidth defaults to one of three sizes depending on the responsive breakpoint of the page (['90vw', '90vw', '600px']).

With those constraints in mind, if you want a variable-width Dialog that renders complex content you should use maxWidth. If your Dialog content must be a specific predefined width, assign values to both props (or else maxWidth will take priority).

The props accept responsive width arrays an well as static strings.

DialogContext

import React, { useContext } from 'react'
import { Button, DialogContext } from '@looker/components'
export function DialogContextDemo() {
return (
<DialogContext.Consumer>
{({ close }) => <Button onClick={close}>Close!</Button>}
</DialogContext.Consumer>
)
}
export function DailogUseContextDemo() {
const { close } = useContext(DialogContext)
return <Button onClick={close}>Close!</Button>
}

DialogContext is a React Context that provides access to functionality without requiring the developer to explicitly manage the Dialog's state. The context provides access to the following:

  • closeModal
  • enableFocusTrap
  • disableFocusTrap
  • focusTrapEnabled

The closeModal method simply allows you to close the Dialog or Popover.

The other methods and values above are for rare use when the focus trap behavior is interfering with the desired behavior, for example, a popover from another library nested inside of a @looker/components Popover or Dialog.

Scroll Lock

A key part of dialog usability is the scroll lock, which disables scrolling on any part of the page except within the dialog. When the Dialog component renders, it registers a scroll lock to the ScrollLockContext in ComponentsProvider, which manages competing scroll locks from other components.

In rare cases, such as nesting a popover from another library inside a Dialog, you may need to temporarily disable the scroll lock:

import { ScrollLockContext } from '@looker/components-providers'
import { useContext } from 'react'
const { activeLockRef, disableCurrentLock, enableCurrentLock } = useContext(
ScrollLockContext
)
function toggleScrollLock() {
if (activeLockRef && activeLockRef.current) {
disableCurrentLock()
} else {
enableCurrentLock()
}
}