Configuration & State Management
Triiiceratops provides a flexible configuration system that works consistently across both the Web Component and Svelte Component implementations.
Configuration Object
Interactive Configuration
You can experiment with these settings in the Live Demo. Open the settings menu (gear icon), tweak the configuration, and then click "Copy Config" to get the JSON for your project.
The viewer accepts a configuration object to customize the UI and behavior. Below is the structure of the configuration object with default values:
interface ViewerConfig {
// Top-level UI Toggles
showCanvasNav?: boolean; // Default: true
viewingMode?: 'individuals' | 'paged'; // Default: 'individuals'
pagedViewOffset?: boolean; // Default: true (Offset paged view by one canvas)
showZoomControls?: boolean; // Default: true
transparentBackground?: boolean; // Default: false
// Toolbar Settings
showToggle?: boolean; // Default: true (Toolbar toggle visible)
toolbarOpen?: boolean; // Default: false (Toolbar expanded)
toolbarPosition?: 'left' | 'right' | 'top'; // Default: 'left'
toolbar?: {
showSearch?: boolean; // Default: true
showGallery?: boolean; // Default: true
showAnnotations?: boolean; // Default: true
showFullscreen?: boolean; // Default: true
showInfo?: boolean; // Default: true
showViewingMode?: boolean; // Default: true
};
// Thumbnail Gallery Settings
gallery?: {
open?: boolean; // Default: false
draggable?: boolean; // Default: true
showCloseButton?: boolean; // Default: true
dockPosition?: 'left' | 'right' | 'top' | 'bottom' | 'none'; // Default: 'bottom'
fixedHeight?: number; // Default: 120
width?: number; // Floating window width
height?: number; // Floating window height
x?: number; // Floating window X position
y?: number; // Floating window Y position
};
// Search Panel Settings
search?: {
open?: boolean; // Default: false
showCloseButton?: boolean; // Default: true
position?: 'left' | 'right'; // Default: 'right'
width?: string; // Default: '320px'
query?: string; // Programmatically set search query
};
// Annotations Settings
annotations?: {
open?: boolean; // Default: false (Sidebar panel)
visible?: boolean; // Default: false (Overlay visibility)
showCloseButton?: boolean; // Default: true
position?: 'left' | 'right'; // Default: 'right'
width?: string; // Default: '320px'
};
// Network Requests
requests?: {
headers?: Record<string, string>; // Extra headers for manifest requests
withCredentials?: boolean; // Use cookies/credentials
};
}
Usage
Passing Configuration
For the Web Component (<triiiceratops-viewer>), configuration is passed as a JSON string via the config attribute.
<triiiceratops-viewer
manifest-id="https://example.org/iiif/manifest.json"
config='{"toolbarPosition": "right", "gallery": {"open": true}}'
></triiiceratops-viewer>
Since attributes are strings, you must JSON.stringify() your config object if setting it via JavaScript:
const viewer = document.querySelector('triiiceratops-viewer');
const config = {
toolbarPosition: 'left',
gallery: { dockPosition: 'right' }
};
viewer.setAttribute('config', JSON.stringify(config));
Reacting to State Changes
The Web Component keeps its internal state in sync with the user's interactions (e.g., opening/closing panels, changing canvas). It dispatches events to notify the host application of these changes.
Events
statechange: Fired when UI state changes (panels open/close, docking, etc.).canvaschange: Fired when the active canvas changes.manifestchange: Fired when a new manifest is loaded.
The event detail contains a ViewerStateSnapshot:
viewer.addEventListener('statechange', (e) => {
const state = e.detail;
console.log('Gallery is open:', state.showThumbnailGallery);
console.log('Current dock side:', state.dockSide);
});
You can use these events to sync your application's UI with the viewer, as demonstrated in src/demo/Demo.svelte.
Passing Configuration
For the Svelte Component (<TriiiceratopsViewer>), configuration is passed directly as a prop.
<script>
import TriiiceratopsViewer from 'triiiceratops/components/TriiiceratopsViewer.svelte';
let config = {
toolbarPosition: 'left',
gallery: { open: true }
};
</script>
<TriiiceratopsViewer {config} manifestId="..." />
Two-Way State Binding
The Svelte component exports a viewerState prop that allows for two-way binding. This gives you direct, reactive access to the internal state.
<script>
import TriiiceratopsViewer from 'triiiceratops/components/TriiiceratopsViewer.svelte';
// This will strictly mirror the internal state
let state = $state();
</script>
<TriiiceratopsViewer
manifestId="..."
bind:viewerState={state}
/>
<div>
Gallery is: {state?.showThumbnailGallery ? 'Open' : 'Closed'}
</div>
If you change the bound configuration prop, the viewer will update. If the user interacts with the viewer (e.g., closes the gallery), the viewerState binding will update your local variable.
Programmatic Search
You can trigger a search programmatically by setting the search.query property in the configuration. This allows you to integrate external search bars or predefined queries.
<triiiceratops-viewer
id="my-viewer"
manifest-id="..."
></triiiceratops-viewer>
<script>
const viewer = document.getElementById('my-viewer');
function search(query) {
// Update config with new query
const config = {
search: {
open: true,
query: query
}
};
viewer.setAttribute('config', JSON.stringify(config));
}
</script>
Note that the viewer does not write back to the config attribute. If the user clears the search in the viewer, your external config object will still have the old query unless you reset it.
Controlling Active Canvas
You can control which canvas is displayed and stay in sync with the viewer's navigation.
To set the canvas, use the canvas-id attribute. To listen for changes, handle the canvaschange event.
<!-- Set initial canvas -->
<triiiceratops-viewer
id="viewer"
canvas-id="https://example.org/initial-canvas"
manifest-id="..."
></triiiceratops-viewer>
<script>
const viewer = document.getElementById('viewer');
// Listen for internal navigation (Next/Prev buttons, Gallery clicks)
viewer.addEventListener('canvaschange', (e) => {
console.log('New Canvas ID:', e.detail.canvasId);
});
// Programmatically change canvas
function goToCanvas(id) {
viewer.setAttribute('canvas-id', id);
}
</script>
The canvasId prop is one-way (Owner -> Viewer). To keep your local state in sync with the viewer, you should bind to viewerState (two-way) to read the authoritative state.
<script>
let canvasId = $state(initialId);
let viewerState = $state();
// Optional: Sync internal changes back to your local canvasId if you need stricter control
$effect(() => {
if (viewerState?.canvasId && viewerState.canvasId !== canvasId) {
canvasId = viewerState.canvasId;
}
});
</script>
<TriiiceratopsViewer
{canvasId}
bind:viewerState
...
/>
Best Practices
- Syncing External Controls: If you build external controls (like the settings menu in the Demo), listen to
statechange(WC) or bindviewerState(Svelte) to keep your controls in sync with the viewer's actual state. - Avoiding Loops: When syncing state back to configuration, ensure you only update your configuration if the value has actually changed to avoid infinite update loops.