Skip to content

0047. A media gallery is a block whose children are media blocks, shown in one view mode

Status: Accepted

Date: 2026-11-03

Context

A media block holds one item. It stores the item's uuid, a view mode, an alignment and an alternative text override, with its caption as its inline content (0006, 0036, 0044), and it opens core's Media Library with one item remaining (DrupalMedia::getEditorSettings()). A site that wants several items side by side has nothing to hold them, and a site converting its galleries makes each one a media block per item in a rule of its own.

A block's props cannot hold a list, since a prop is a boolean, a number or a string, so a list of items has to be a block's children. BlockNote lets any block be nested under any other. In 0.57.0 only a layout block (layoutOnly: true) may narrow the children it takes, and then only to layout block types: every regular block is the same ProseMirror node, blockContainer, so no schema can say that a block's children are media blocks (ChildrenConfig in @blocknote/core types/src/schema/blocks/types.d.ts). Keeping other blocks out is the module's own work.

A media block's view mode is curation, strict where the author chooses and lenient where the page renders (0015), and the format's settings for drupalMedia list the media types and view modes it permits. Every media block shows a preview the server renders, and its functions are in the formatting toolbar and the Alt+F10 block menu (0019). The block menu offers the groups of the selected block alone (blockMenuGroups() in js/src/blockmenu.tsx, 0014), and a block with no content of its own never holds the caret. A lightbox is a site's concern, which several contributed modules provide.

Decision

A gallery is a block in blocknote_media, drupalMediaGallery, with no content of its own, whose children are drupalMedia blocks only. It has two props: columns, 2, 3 or 4, by default 3, and viewMode, applied to every item and chosen from the view modes the format permits for media, curated as a media block's is (0015). An item keeps its own caption and alternative text; its own view mode and alignment are ignored inside a gallery. The editor moves any other block that is dropped or nested into a gallery out of it, to right after it, and the save refuses a gallery holding one, as a backstop.

An author builds a gallery from the Media Library. The slash menu's Gallery opens the library allowing several items, and the choice becomes a gallery with one child per item, in the order they were picked. Add media appends more. Items reorder by dragging, as any block does, or with the block menu's Move up and Move down. Removing the last item removes the gallery. Add media, the columns and the view mode are in the formatting toolbar.

The Alt+F10 block menu offers the gallery's own groups, Add media, Columns and View mode, when the selection is on the gallery or on any media block inside it, after the media block's own groups in the latter case, so that every function of the gallery has a keyboard route from wherever the caret can be (0011).

In the editor a gallery is its items' own previews in a grid of its column count, each with its caption field. The gallery requests no preview of its own.

On the page a gallery is a list of figures:

<div class="blocknote-block blocknote-block--drupal-media-gallery blocknote-gallery--cols-3"><ul class="blocknote-gallery__items"><li><figure class="blocknote-block blocknote-block--drupal-media">…</figure></li>…</ul></div>

Each li holds the item's usual figure (docs/rendering.md section 5), rendered in the gallery's view mode and with no alignment class. blocknote-gallery--cols-<n> carries the column count. The module's stylesheet for the page lays the list out as a grid, which a theme may override. There is no lightbox and no front-end JavaScript: the view mode decides what an item renders, so a site that wants an item to zoom or to link somewhere gives it a view mode that does.

The converter recognizes no gallery markup. MediaConversion, the service a site's rule hands media markup to (docs/extending.md section 14), gains a method that builds a gallery from a list of media items, so a site rule that recognizes its own gallery markup builds the block with one call. A target format without the gallery block gets one media block per item instead, and the report says so.

Amended 2026-11-03. The list in the HTML above carries role="list", as the gallery's template prints it and docs/rendering.md gives it: <ul class="blocknote-gallery__items" role="list">, because the module's stylesheet removes the list's markers and Safari then drops its semantics.

Amended 2026-11-03. An item stays in its gallery through the keyboard as well. BlockNote 0.57.0 moves a child out a level on Shift+Tab, on the block menu's Outdent and on Enter in its empty content, which takes the items after it along as its children, so the gallery's specification sets BlockNote's experimental_keyboard option to { childrenCanOutdent: false, emptyChildEnter: 'stay' } (@blocknote/core types/src/schema/blocks/keyboard.d.ts). Enter in an item's empty caption then gives the item a paragraph after it, which the editor moves out to right after the gallery, and the caret goes with it, as it does with any block the editor moves out. The block menu offers an item neither Indent nor Outdent; its Move up and Move down reorder the items and are not offered at the gallery's ends, and a block next to a gallery moves past it as a whole instead of into it, from the block menu and from Shift+Mod+ArrowUp and Shift+Mod+ArrowDown alike. The gallery goes on the change that takes its last item away; a gallery that holds no item to begin with, inserted or stored that way, stays.

Alternatives considered

A list of items in one prop. Rejected. A prop cannot hold a list, and a string of uuids would give up everything a media block already does for one item: its preview, its caption, its alternative text, its validation and its conversion.

A view mode for each item. Rejected. One view mode keeps the grid even.

A lightbox in the module. Rejected. A site gets one from a contributed module or through a view mode, and the page stays free of the module's JavaScript (0004).

A preview of the whole gallery from the server. Rejected. Each item already has one, and a grid of them shows what the page will look like.

Recognizing gallery markup in the converter. Rejected. There is no common gallery markup: sites use placeholders of their own, which a rule of the site's own reads better than a guess by the module.

Consequences

An item in a gallery is a media block like any other, so its preview, caption, alternative text, validation, referenced entities and conversion are the media block's own. What changes inside a gallery is that its view mode and alignment are not used; they stay stored, and an author who moves the item out of the gallery finds them again.

The module carries code BlockNote's schema cannot replace: moving another block out of a gallery, removing a gallery left with no item, and refusing on save a gallery that holds another block.

The block menu no longer offers the selected block's groups alone: for a media block inside a gallery it offers the gallery's too, after the media block's own.

A format that enables the gallery governs its items through the media block's own settings: the media types it permits, and the view modes, which the gallery's single view mode is chosen from. A format that stops enabling the gallery renders nothing for it, its items included, as it renders any block it no longer enables (docs/rendering.md section 2).

docs/rendering.md gains the gallery's envelope, a div holding a ul with an li per item and its children inside, and its two classes.

References

  • Drupal core: core/modules/media_library/src/MediaLibraryState.php.
  • BlockNote 0.57.0: @blocknote/core types/src/schema/blocks/types.d.ts (ChildrenConfig), types/src/schema/blocks/children.d.ts.
  • This module: js/src/blockmenu.tsx, modules/blocknote_media/src/Plugin/BlockNoteBlock/DrupalMedia.php, modules/blocknote_media/src/MediaLibraryBlockNoteOpener.php, modules/blocknote_media/src/Convert/MediaConversion.php, modules/blocknote_media/js/library.ts, modules/blocknote_media/js/toolbar.tsx, modules/blocknote_media/js/blockmenu.ts, modules/blocknote_media/js/block.tsx, css/blocknote.content.css.
  • docs/rendering.md sections 2 and 5, docs/extending.md section 14.
  • 0004, 0006, 0010, 0011, 0014, 0015, 0019, 0036, 0044.