Raft 设计系统

组件 · 浮层

Lightbox

A full-screen viewer over the scrim for images and attachment previews, with previous and next, thumbnails and one button to close.

稳定也叫 Image viewer, Media viewer, Attachment preview
import { Lightbox } from "@botiverse/raft-ui";
本页尚未翻译
译文完成之前,这里显示英文原文。 阅读英文版

A lightbox shows an image or a file preview at full size over the whole window: the image on a full-screen layer-backdrop, previous and next, and one icon button to close (Built from existing parts). Use it when someone opens an image or an attachment from a message. It is for media and previews only.

lightbox/compositions/image-lightbox-shell

When to use

SituationUse
Viewing an image, a screenshot or a video at full sizeLightbox, image shell
Previewing an attached file (an HTML page, a document) at full sizeLightbox, attachment shell
A decision, a form or anything that is not mediaDialog
Details people read beside the pageDrawer
The attachment in the message itselfMessageAttachment

Anatomy

  • Lightbox: the root. It holds whether the lightbox is open. Required.
  • LightboxTrigger: what opens it, usually the image or the file card in the message.
  • LightboxContent: the full-screen layer, with the scrim behind it. Required.
  • LightboxTitle: the file name.
  • LightboxClose: the close button. Required.
  • LightboxStage: the area that centers the media. Required.
    • LightboxMedia: the image or video, at most 80% of the window's height and 86% of its width.
    • LightboxNavigationButton: previous (direction="previous") and next (direction="next"), 44px buttons 32px from the left and right edges.
    • LightboxInfoDock with LightboxInfoBar: a small floating bar near the bottom, on layer-popover with shadow-float, holding LightboxInfoTitle (the file name) and LightboxInfoActions (such as Download). It is a floating toolbar, 36px tall like the message hover toolbar: its buttons are 28px, 4px inside it and 4px apart, with radius-chip, and a 44px tall hit area on a touch screen that reaches only half the gap toward a neighbour (Shape).
    • LightboxThumbnailStrip with LightboxThumbnails: 48px thumbnails along the bottom; active marks the one shown.
  • LightboxToolbar: the attachment shell's top bar instead of the floating close button, on layer-canvas with a line-seam under it. It holds LightboxHeaderMeta (a LightboxHeaderLabel or Badge naming the preview type, then LightboxTitle) and LightboxActions, with LightboxClose last.
  • LightboxHeader: a plain top row for a title and actions, for shells that need neither toolbar nor floating close.

Variants

VariantUse for
Image shell: LightboxClose directly in LightboxContentImages and video. The close button floats at the top right; the image has the whole window
Attachment shell: LightboxToolbar above LightboxStageA file preview that fills the stage, such as an HTML page in an iframe. The toolbar names the file and holds its actions and the close button
lightbox/compositions/attachment-preview-shell

States

  • First and last item: previous or next is disabled. It stays focusable (aria-disabled) and ignores clicks.
  • Thumbnails: the shown item has a solid edge; the others are dimmed until hovered.

Behavior

  • A lightbox appears and disappears without animation, like the other centered overlays (Motion).
  • Esc, the close button, a click on the scrim and Cmd+W (Ctrl+W) close it. Cmd+W closes the lightbox, not the browser tab; pass closeOnModW={false} to leave the shortcut to the browser.
  • The close button and the bars keep clear of the phone's safe areas.
  • The caller keeps which item is shown. Previous, next, the thumbnails and the arrow keys all change that index.

Content

  • Title the lightbox with the file name. A long name truncates at the end.
  • Name the preview type in the toolbar's label in sentence case: HTML preview.

Accessibility

  • Lightbox wraps the Base UI Dialog. It provides the dialog role, the focus trap and Esc; raft-ui adds the Cmd+W shortcut.
  • LightboxTitle is plain text, not the dialog's name. Name the dialog yourself: aria-label on LightboxContent, or a render element with one.
  • LightboxContent doesn't move focus when it opens or return it when it closes (initialFocus and finalFocus are false). Pass them when keyboard users open the lightbox, so focus lands in it and goes back to the trigger.
  • Give LightboxClose, each LightboxNavigationButton and each icon-only action an aria-label: "Close", "Previous image", "Next image", "Download".
  • Bind the Left and Right arrow keys to previous and next while the lightbox is open.
  • Give each LightboxThumbnail an aria-label ("Show product-shot.png"). active changes only how it looks: mark the shown one with aria-current="true".
  • Give the image an alt that describes it, and an iframe a title.

Rules

  • Don't build a media viewer from a Dialog, and don't put anything other than media or a file preview in a Lightbox.
  • Give the lightbox one close button, at the top right (Navigation).
  • In the toolbar, a framed button ends its shape on the 16px margin; a frameless icon button, as the last action or the close, ends its icon box there and its hit area hangs past it (Alignment).
  • In Raft Chat every file opens in the attachment shell, images included, so each file type has the same toolbar (File viewer).
  • Don't add colors or lines beyond the scrim, the info bar and the toolbar (Built from existing parts).

API

Prop类型默认值
childrenReactNode
closeOnModWbooleantrue
defaultOpenWhether the dialog is initially open.booleanfalse
defaultTriggerIdID of the trigger that the dialog is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog.string
disablePointerDismissalWhether to prevent the dialog from closing on outside presses. For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it.booleanfalse
modalDetermines if the dialog enters a modal state when open. - `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.boolean | "trap-focus"true
onOpenChangeEvent handler called when the dialog is opened or closed.(open: boolean, eventDetails: Dialog.Root.ChangeEventDetails) => void
onOpenChangeCompleteEvent handler called after any animations complete when the dialog is opened or closed.(open: boolean) => void
openWhether the dialog is currently open.boolean
triggerIdID of the trigger that the dialog is associated with. This is useful in conjunction with the `open` prop to create a controlled dialog. There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set).string

LightboxActions

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxClose

Prop类型默认值
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxContent

Prop类型默认值
finalFocusDetermines the element to focus when the dialog is closed.boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void)false
initialFocusDetermines the element to focus when the dialog is opened. By default, focus moves to the first tabbable element inside the popup, except when the dialog is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.boolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | HTMLElement | null | void)false
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxHeader, LightboxHeaderLabel, LightboxHeaderMeta, LightboxInfoActions, LightboxInfoBar, LightboxInfoDock, LightboxInfoTitle, LightboxMedia

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxNavigationButton

Prop类型默认值
direction (required)"next" | "previous"
disabledboolean
loadingLabelstring
focusableWhenDisabledWhether the button should be focusable when disabled.booleanfalse
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxPortal

Prop类型默认值
containerA parent element to render the portal element into.HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null>
keepMountedWhether to keep the portal mounted in the DOM while the popup is hidden.booleanfalse
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxStage

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxThumbnail

Prop类型默认值
activebooleanfalse
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxThumbnailStrip, LightboxTitle, LightboxToolbar

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

LightboxTrigger

Prop类型默认值
handleA handle to associate the trigger with a dialog. Can be created with the Dialog.createHandle() method.Dialog.Handle<unknown>
idID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop).string
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
payloadA payload to pass to the dialog when it is opened.{}
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

改动

  • 0.1.0 · AddedExtended Lightbox with thumbnail strip and related chrome parts; added ComboboxTriggerCount and ContextMenuPopup.