docs/overview/changelog
Changelog
What changed in each release.
The package follows semver. Until 1.0.0, a minor version (0.x.0) may break the API; each
breaking change is listed under its release.
v0.4.0#
October 22, 2026.
New features#
- Cropper, at
@logic-ui/react/cropper: an image cropper ported from advanced-cropper and react-advanced-cropper, in one headless entry point.Cropper.Root,Viewport,Image,Stencil,Handle,GridandPreviewrender no styles: they exposedata-*attributes and CSS variables. One pointer gesture engine resizes from corners and edges, moves the crop, pans the image, pinches and zooms with the wheel.ZoomIn,ZoomOut,Rotate,FlipandResetact on it, the keyboard moves, resizes and zooms, andactionsRefdraws the crop withgetCanvas().stencilSizekeeps the crop a fixed size on screen while the image moves behind it, andCropper.Viewport's padding keeps the crop clear of bars laid over it.
v0.3.0#
October 12, 2026.
Breaking changes#
Lightbox.Media'swidthandheightset the box's shape when both are given, so every slide can keep the same shape. The loaded media's size is used only when they are missing.Lightbox.Mediakeeps theobject-fityou set on your media. It is contained only when you set none, instead of always.
New features#
fillonLightbox.Mediamakes the box fill the slide, inside its padding, whatever the shape of the media. The flights and the pull to dismiss use that box.
Fixes#
- A flick past the first or last item springs back at the normal pace, instead of snapping back in about 30 ms.
- A zoomed image keeps its zoom until it has slid out of sight, instead of snapping to 1x while it slides out. Swiping back to it before then keeps its zoom.
v0.2.0#
October 12, 2026.
Breaking changes#
- Built on
@base-ui/react1.9.0 (was 1.8.0) and@base-ui/utils0.5.0. Select, Combobox and Autocomplete unmount on close whether or notactionsRefis set; calleventDetails.preventUnmountOnClose()inonOpenChangeto keep them mounted.onItemHighlightedreceives the originating event. See the Base UI 1.9.0 release notes. Galleryis now Lightbox, at@logic-ui/react/lightbox. Every part, type, hook and constant is renamed (GalleryRoot→LightboxRoot,GALLERY_ZOOM_SCALE→LIGHTBOX_ZOOM_SCALE), and the CSS variable--gallery-dismiss-progressis now--lightbox-dismiss-progress. The lightbox is the full-screen viewer only: the page around the triggers is yours.- Items are picked by value, not by index.
Roottakesvalue/defaultValue/onValueChange(the value of the item shown, nevernull: it stays on the last item after closing, and defaults to the first) instead ofindex/defaultIndex/onIndexChange. Whether the viewer is open stays apart, inopen/defaultOpen/onOpenChange. An item's value is itsid, or what the newitemToValuereturns.Triggertakesvalueinstead ofindex; pressing it callsonValueChangewhen it shows another item, thenonOpenChange. The open item stays open when items are added, removed or reordered. Itemis nowSlide, and takes noindex: return it from the function passed toViewport. With thumbnails, the slides are their tab panels.Imageis replaced byMedia, which wraps your own<img>,<video>or<iframe>:<Lightbox.Media width={photo.width} height={photo.height}><img src={photo.src} alt={photo.alt} /></Lightbox.Media>. It takes the naturalwidthandheight; thesrcandaltgo on your element. The whole box flies and follows the pull to dismiss, and only an<img>zooms.LightboxImageStatusisLightboxMediaStatus.- Items can have any shape.
GalleryItemDatais removed. The parts take what they need as props, andDescriptiontakes a function child to show the item's caption:{(photo) => photo.caption}. Valueis nowCounter.ZoomValue's function child receives its state,{(state) => state.scale}, instead of the scale.- Removed
ListandMore. Lay out the triggers with your own elements. - Removed
ToolbarandSeparator. Use Base UI's Toolbar and render each action as aToolbar.Button:<Lightbox.Next render={<Toolbar.Button />} />. - Removed
DeleteandDownload. Build them as buttons in the popup. Image'sdata-loadedis replaced bydata-loadinganddata-error, onMediaand itsSlide.data-draggingis nowdata-swiping, onPopup,Backdrop,ViewportandThumbnailList, like Base UI's drawer.ThumbnailList's state field isswiping.data-popup-openmarks the trigger the image will fly back to: the one of the item shown, or the onecloseTargetpicks. Before, it marked every trigger of the item shown.onValueChangeandonOpenChangereceiveeventDetailsas their second argument, like Base UI's callbacks.- Removed
loadImage,loadLightboxImageandLIGHTBOX_PRELOAD_TIMEOUT. The viewer loads its media itself: before it opens, it is mounted out of sight until the<img>or<video>inMediahas loaded (a video, its size), for up toLIGHTBOX_OPEN_TIMEOUT(3 s). The trigger hasdata-pendingmeanwhile. The thumbnail and the viewer can show different URLs with no extra code. ViewportandSlideno longer clip. Addoverflow-hiddento the viewport in a viewer smaller than the screen.- Closed sets are string unions, not enums, named after their part like Base UI's. Write the
strings (
"loading","open","left") instead ofLightboxMediaStatus.Loadingand the like.LightboxPhaseis nowLightboxRootPhase, andLightboxActivationDirectionisLightboxRootActivationDirection.ThumbnailList'sorientationis typedLightboxThumbnailListOrientation. - The CSS variable namespaces end in
CssVariables, like Base UI's:LightboxPopupCssVariablesinstead ofLightboxPopupCssVars, and the same forBackdrop,Slide,ThumbnailIndicatorandViewport.
New features#
onOpenChangecan return a Promise, and the viewer waits for it: up to 3 s before it opens, 300 ms before it closes (LIGHTBOX_OPEN_TIMEOUT,LIGHTBOX_CLOSE_TIMEOUT). Use it to get something ready, such as moving a live element into the viewer.eventDetails.cancel()works until the wait ends, after anawaittoo, and a cancelled change never happened.Lightbox.createHandle()links triggers placed outsideRootto it, like Base UI's detached triggers, and opens or closes the lightbox from code.- Any media.
Mediashows a video or an embed as well as an image, and reads its loading state from the media's own events. A video pauses when its slide is no longer shown. ThumbnailListandThumbnail: a strip of thumbnails inside the viewer, a tab list that is a single tab stop, witharia-selectedon the item shown.ThumbnailIndicatoris one element that glides to the active thumbnail, with its box as CSS variables.Caption: a slide's own text, which moves with it and describes it for screen readers.- Animation attributes.
Popup,Viewport,Slide,Title,Description,Counter,CaptionandThumbnailIndicatorhavedata-activation-direction(left,rightornone), the side the item shown came from.TitleandDescriptionwith a function child,CounterandCaptionhavedata-starting-stylefor a frame when the item changes, to animate the new text in.Titletakes a function child, likeDescription. Popup'sclassName,styleandrenderfunctions receivezoomed,controlsHiddenandactivationDirection.Viewportis a labelled carousel region.- Content marked with Base UI's
data-base-ui-swipe-ignorekeeps its drags, such as a 3D model that rotates: the viewer doesn't swipe or pull to dismiss from it."x"or"y"keeps only the drags along that axis. - The arrow keys stay with a widget inside the popup that uses them itself, such as a Base UI toolbar, a text field or a video player, instead of also changing the image.
- Where the image lands.
closeTargetonRootpicks the trigger the image flies back to and focus returns to:"active"(the item shown, the default),"opener"(the trigger that opened the viewer) or"nearest"(the nearest item with a trigger, for a "+5" tile).scrollToTrigger(on by default) scrolls the page behind the viewer to keep that trigger in view. - Crossfade. When the image flies to or from a trigger that shows something else (another
item, or a trigger with the new
crossfadeprop, such as an avatar or a tile with a count), a copy of the trigger flies along and fades, so the image grows out of its look and turns back into it on the way home.Triggerhasdata-crossfade. - Change reasons.
eventDetails.reasontells what changed the item ("swipe","trigger-press","escape-key"…), andeventDetails.cancel()keeps the current item: a cancelled swipe or pull to dismiss springs back.onOpenChangeCompleteis called once the image has landed. - A smoother flight. It is computed on screen, so the shape and corners change evenly;
a flight cut short starts the next from where the image is; after a pull to dismiss, the
flight back starts at the speed of the finger.
--lightbox-flight-durationand--lightbox-flight-easingonPopupandBackdroplet transitions go with it, and--lightbox-flight-movement-x,-yand--lightbox-flight-scaleonPopuptell where the image flies, so other content can go there too. - Gesture variables.
Popupgets--lightbox-swipe-movement-x,--lightbox-swipe-progressand--lightbox-swipe-strengthduring a swipe,--lightbox-zoom-scaleand--lightbox-zoom-progress, and, withBackdrop,--lightbox-dismiss-movement-xand-y. - Custom transitions. Each
Slidehas--lightbox-slide-progress, its distance from the centre in slides, and is placed withtranslate, leavingtransformfree for a cube, a fade or a coverflow.Viewport'sneighborsrenders more items on each side (1 by default), and--lightbox-swipe-distanceon it sets how far the finger travels for one slide, for slides that sit closer together than the viewport is wide. - Changing
valuewhile the viewer is open slides to the new item, as Next does. Popuptakes focus when it opens, so its keys work at once; passinitialFocusto focus another element.- Optional props accept
undefined, for apps withexactOptionalPropertyTypes.
From Base UI 1.9.0#
- Every component exports its
data-*attributes and CSS variables as namespaces, such asDialogPopupDataAttributesandDialogPopupCssVariables. Menucan filter its items withMenu.FilterProviderandMenu.Input(preview).data-base-ui-swipe-ignoretakes"x"or"y"in Drawer too.
v0.1.0#
October 8, 2026. The first release.
New components#
- Gallery (now Lightbox): thumbnails that open a full-screen image viewer. The image flies out of its thumbnail and back, and the viewer handles swipe, pinch to zoom, double tap, pan, pull to dismiss and the keyboard. Comes with toolbar parts for navigation, zoom, download and delete.
- Clipboard: a button that copies a value and shows that it
was copied.
Root,TriggerandIndicatorexposedata-copied.
Core components#
- Dialogs, menus, popovers, selects, tabs and the other core components, each under its own
path, such as
@logic-ui/react/dialog. @logic-ui/react/utilsexports the hooks the primitives are built on, such asuseControlled,useStableCallbackanduseTimeout.
Requirements#
- React 19.
- Built on
@base-ui/react1.8.0.