picola
Lightbox & image viewer

Open every image
beautifully.

A fast, type-safe, extensible lightbox — a dependency-free core with a first-class Svelte 5 adapter. Pinch to zoom, drag to dismiss, and transitions that stay smooth even while images decode.

Read the docs
~15.6KB

min+gzip, icons included

~11KB

the dependency-free core, min+gzip

0

runtime dependencies in the core

0

long tasks while navigating

Bundle figures are min+gzip; the long-task count is from picola’s benchmark harness.

Features

Where picola is different.

Sensible defaults, a small footprint, and an escape hatch when you need one.

Compositor-driven transitions

Opening, closing, the clip reveal and slide-steps run on the compositor via the Web Animations API, so they hold their frame rate even while images decode.

Fly from the thumbnail

Open and close animate from the source thumbnail. For an object-fit: cover crop, the full image is revealed with an animated clip instead of a jump.

Memory-disciplined

Only the active slide ±1 stays mounted; images outside the window are detached so the browser reclaims their decoded pixels.

Progressive, seamless loading

Placeholder first, full resolution deferred to a zoomintent event, then swapped in with zoom and pan preserved. Reactive slides for pagination.

Gestures that feel native

Focal-point pinch / double-tap / wheel zoom, iOS-style rubber-banding, velocity flicks, and drag- or pinch-to-dismiss with progress you can read from CSS.

Styling that never fights back

Zero-specificity :where defaults and flat single-class selectors: override by normal cascade order — no !important, and no @layer to lose against your resets.

Genuinely Svelte 5

Toolbar and caption via snippets and real components; a generic Slide<T> carries your data through typed events. No SVG-string injection, no manual mount.

Dependency-free core

Zero dependencies, owning gestures, physics and transforms. The Svelte adapter is the reference build — write one for any framework.

Live demo

Try it right here.

Real picola, running in a Svelte island. Click any photo, then pinch, zoom, drag down to dismiss, or use your keyboard.

Tip: drag the image downward to dismiss it.

Quick start

A complete viewer in a handful of lines.

Install, import the stylesheet, pass your slides. Everything else is optional refinement.

App.svelte
<script lang="ts">
import { Lightbox, type Slide } from 'picola/svelte';
import 'picola/picola.css';
const slides: Slide[] = [
{
src: '/photos/1.jpg',
placeholder: '/photos/thumb/1.jpg',
width: 2400,
height: 1600,
alt: 'A river running through a valley at dusk.'
}
];
let open = $state(false);
</script>
<button onclick={() => (open = true)}>Open gallery</button>
<Lightbox bind:open {slides} />
See all recipes
Theming

Yours in a few custom properties.

Every control is tuned through CSS custom properties on the .pcl root — no !important, no fighting the cascade.

  • --pcl-backdrop
  • blur(16px)--pcl-backdrop-filter
  • --pcl-chrome-color
  • --pcl-button-bg
  • 3--pcl-caption-lines
  • 48px--pcl-arrow-size
.pcl
.pcl {
--pcl-z: 2000;
--pcl-backdrop: rgba(10, 10, 16, 0.55);
--pcl-backdrop-filter: blur(16px);
--pcl-chrome-color: #eafaff;
--pcl-button-bg: rgba(92, 202, 233, 0.16);
--pcl-caption-lines: 3;
}

Ready to open beautifully?

Install picola and ship a polished image experience.