Skip to main content
Photo Sphere Viewer is a plain JavaScript library that works in any environment. When using it inside a component-based framework, you need to manage the viewer lifecycle manually — create it when the component mounts, and destroy it when the component unmounts.
Always call viewer.destroy() when the component is unmounted. Failing to do so causes memory leaks and may leave dangling event listeners.
The community maintains react-photo-sphere-viewer by Elia Lazzari — a ready-made React wrapper you can use instead of writing your own.

Wrapper patterns

The approach is the same across all frameworks:
  1. Declare a container element in the template.
  2. After mount, instantiate Viewer with the container reference.
  3. On unmount, call viewer.destroy().
import { useEffect, useRef } from 'react';
import { Viewer } from '@photo-sphere-viewer/core';
import '@photo-sphere-viewer/core/index.css';

interface Props {
  panorama: string;
}

export function PanoramaViewer({ panorama }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const viewer = new Viewer({
      container: containerRef.current!,
      panorama,
    });

    // Destroy the viewer when the component unmounts
    return () => {
      viewer.destroy();
    };
  }, [panorama]);

  return <div ref={containerRef} style={{ width: '100%', height: '500px' }} />;
}
The effect dependency array includes panorama. This means the viewer is recreated whenever the panorama prop changes. If you want to update the panorama without recreating the viewer, use viewer.setPanorama() inside the effect instead.

Accessing the viewer instance

Once created, you can hold a reference to the viewer and call any method on it — for example to change the panorama, listen to events, or use plugins:
// Change panorama after creation
viewer.setPanorama('new-panorama.jpg');

// Listen to viewer events
viewer.addEventListener('position-updated', ({ position }) => {
  console.log(position.yaw, position.pitch);
});

// Access a plugin
const markersPlugin = viewer.getPlugin(MarkersPlugin);
markersPlugin.addMarker({ id: 'point', position: { yaw: 0, pitch: 0 } });
See Methods and Events for the full API.

Plugins and adapters

Plugins and adapters are passed to the Viewer constructor in the same way regardless of framework:
import { Viewer } from '@photo-sphere-viewer/core';
import { MarkersPlugin } from '@photo-sphere-viewer/markers-plugin';
import '@photo-sphere-viewer/markers-plugin/index.css';

new Viewer({
  container: containerRef.current,
  panorama: 'panorama.jpg',
  plugins: [
    [MarkersPlugin, {
      markers: [
        {
          id: 'point',
          position: { yaw: '45deg', pitch: '10deg' },
          tooltip: 'A marker',
        },
      ],
    }],
  ],
});

Build docs developers (and LLMs) love