ComponentViewer

API documentation — jQuery plugin for attachment and media preview in an overlay

Open example

Overview

ComponentViewer is a jQuery plugin that opens attachments (images, video, audio, PDF, inline content, and more) in a shared full-screen overlay with a consistent header, footer, and toolbar. It is designed for feed- or post-style UIs where each container (e.g. a post or card) has its own set of items; the plugin is instantiated per container, and one global overlay is reused.

Features include:

  • Multiple content types: image (with zoom/pan), video, audio, PDF, inline/code, error, HTML, and unsupported fallback
  • Configurable toolbar with built-in Download and zoom, plus custom toolbarItems and onToolbar
  • Optional poll UI (radio/checkbox) above the toolbar for items with pollOptionLabel
  • Dark/light theme with optional theme toggle
  • Optional WCAG behavior: focus trap, focus save/restore, ARIA dialog semantics
  • Loop on/off, optional counter, adjacent image preload, overlay fullscreen, touch swipe nav / swipe-to-close
  • Optional tooltips on controls (canShowTooltip), keyboard shortcuts popup (shortcutsPopup)

License: MIT


Demo

Try the plugin in your browser with the full example page. It includes all content types (image, video, audio, PDF, inline, error, HTML), toolbar customisation, themes, poll options, loop and counter options, and image failure handling.

Open index.html — open this file in a browser to see multiple demo cases. Use the programmatic API buttons at the bottom to open specific items (e.g. Case 1: Image, Case 2: PDF, Case 14: Invalid URL).

The example page uses jQuery 3.7, jPlayer, and PDF.js (loaded from CDN). Without jPlayer or PDF.js, the plugin falls back to native <video>/<audio> and an iframe for PDF; use your own minimal HTML page with only jQuery + the plugin to try that. For other jQuery or library versions, point your script tags at the builds you need and use the same index.html markup as a reference.


Getting Started

Installation

Required: jQuery (1.7+ or 2.x / 3.x).

Optional:

  • jPlayer — for rich video/audio playback. If not loaded, the plugin falls back to native <video> / <audio>.
  • PDF.js — for PDF rendering with page navigation, thumbnails, zoom, rotate. If not loaded, the plugin falls back to an iframe.

Include the plugin and stylesheet after jQuery:

<link rel="stylesheet" href="component-viewer.css" />
<script src="jquery.min.js"></script>
<!-- Optional: jPlayer, PDF.js -->
<script src="component-viewer.js"></script>

Quick start

1. Mark up your items with a common selector (default .cv-item) and use data-* for type, source, and title:

<div id="my-gallery">
  <a class="cv-item" data-type="image" data-title="Photo.jpg" href="https://example.com/photo.jpg">
    <img src="https://example.com/thumb.jpg" alt="" />
  </a>
  <div class="cv-item" data-type="pdf" data-title="Doc.pdf" data-src="https://example.com/doc.pdf" data-ext="PDF">PDF</div>
</div>

2. Initialize the viewer on the container:

$('#my-gallery').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'path/to/pdf.worker.min.js' }
});

3. Click any item to open it in the overlay; use prev/next to move between items.

Minimal copy-paste example

Below is a single block you can drop into an HTML file to try the plugin immediately (ensure jQuery and the plugin scripts/styles are loaded):

<!-- HTML: one image item -->
<div id="minimal-demo">
  <a class="cv-item" data-type="image" data-title="Sample" href="https://picsum.photos/800/600">
    <img src="https://picsum.photos/200/150" alt="" />
  </a>
</div>

<script>
$('#minimal-demo').componentViewer({ toolbar: { download: true, zoom: true } });
</script>

Building with the plugin

To integrate ComponentViewer into your app:

  1. Choose a container — e.g. the element that wraps one post or one set of attachments.
  2. Ensure each clickable attachment is a direct or nested element matching selector (default .cv-item).
  3. Provide item data — either via data-type, data-src / href, data-title, etc., or via the itemData callback for full control.
  4. Call $(container).componentViewer(options) once per container. Each container gets its own list of items (all elements matching the selector inside it) and its own index; the overlay is shared.
  5. Optional: Use onRender to render custom content and return a custom toolbar; use onToolbar to modify the built-in toolbar; use onDownload to customize download behavior.

File structure

The ComponentViewer project includes the following files:

component-viewer-v2/
├── component-viewer.js      # Plugin script (jQuery plugin, overlay, built-in renderers)
├── component-viewer.css     # Styles for overlay, header, stage, toolbar, carousel, etc.
├── documentation.html       # API documentation (this file)
├── index.html             # Full demo with all content types and options
└── README.md                # Project overview and usage
FileDescription
component-viewer.jsMain plugin: overlay UI, keyboard/click handling, built-in renderers (image, video, audio, PDF, inline, HTML, error), toolbar resolution, carousel, slideshow, stage-only mode.
component-viewer.cssLayout and theme styles for the overlay, shell, header, footer, stage, nav buttons, carousel, zoom widget, and light/dark theme.
documentation.htmlAPI reference and configuration options.
index.htmlComprehensive examples (images, video, audio, PDF, inline, carousel, slideshow, stage-only, etc.) with programmatic API buttons.
README.mdQuick start and usage summary.

Options reference

All options are optional. Defaults are available at $.fn.componentViewer.defaults. Pass an object to componentViewer(options) to override.

Quick reference

One-line summary of the main options. See the tables below for types, defaults, and full descriptions.

OptionSummary
itemsArray of item objects — use instead of DOM elements
selectorCSS selector for items (default .cv-item)
loopWrap prev/next at first/last item
overlayCloseClose on backdrop click
keyboardNavEscape, arrows, shortcuts
isRTLEnable RTL UI behavior (layout, arrows/swipe, carousel direction)
minimizeMinimize to floating restore icon
showCounterShow "1 / N" in header
stageOnlyMinimal overlay (stage + nav only)
carouselThumbnail strip below stage
slideshowAuto-advance with interval
theme / themeToggleDark/light theme
toolbarDownload, zoom, extractText (default false) toggles
zoommin/max/step, wheel, loadHighResUrlAt for hi-res swap
markdown{ toggleRawView } — raw vs rendered toggle
inline / onInlineHtmlSyntax highlight (Highlight.js), custom HTML
pdfPDF.js worker, text layer, onPrint, spreads
videoHD URL, beforeVideoPlay, canShowHDButton (jPlayer)
itemDataCustomize item per element
wcagFocus trap, ARIA
pollOptionRadio/checkbox poll row
showAttachmentCommentComment overlay (item.comments)
canShowExtractTextCallback to show "Extract text" button for images
extractTextCallback to perform OCR; result rendered as overlay
beforeOpenOverlay opens first with loader; async logic then proceed → item or gate (toolbar hidden until content loads)
beforeCollectItemsOptional hook before each item list rebuild; during the hook read viewer._beforeCollectContext (e.g. $element on click)
onOpen, onClose, onComplete, onCleanupLifecycle callbacks
onDownload, onRender, onToolbar, onErrorCustom behavior

General options

Each Description is a short bullet list for easier scanning.

OptionTypeDefaultDescription
itemsarray | nullnull
  • Non-empty array → use these objects as the item list (no DOM collection).
  • Each item shape: { type, title, src, downloadUrl, ... }.
  • Use for programmatic flows (charts, iframes) with no .cv-item nodes.
  • null or empty → collect items from the container via selector.
selectorstring'.cv-item'
  • CSS selector for attachment elements inside the viewer container.
  • Each match becomes one item.
  • Ignored when items is a non-empty array.
loopbooleantrue
  • true → prev on first wraps to last; next on last wraps to first.
  • false → prev/next buttons hidden on first/last item.
overlayClosebooleantrue
  • true → clicking the dimmed backdrop closes the overlay.
swipeToClosebooleantrue
  • true → downward swipe on the stage closes (touch / mobile).
  • Only applies when overlayClose is true.
  • Does not change desktop mouse behavior.
keyboardNavbooleantrue
  • trueEsc closes; / prev/next item.
  • When isRTL is true, arrow-key mapping is mirrored ( next, previous).
  • Space, M, D, and custom toolbar shortcuts apply when relevant.
  • Full list: Keyboard shortcuts.
shortcutsPopupbooleantrue
  • true? (Shift+/) opens a context-aware shortcuts popup.
  • false → disable the popup and that key binding.
swipeNavbooleantrue
  • true → horizontal swipe on the stage → prev/next (touch).
  • When isRTL is true, swipe direction for prev/next is mirrored.
  • Images at zoom 1: swipe navigates; zoomed in: one-finger pan.
  • Desktop: use arrows or on-screen prev/next (unchanged).
canShowTooltipbooleantrue
  • true → hover tooltips on header/footer/toolbar controls (custom hover UI, not title).
  • Custom toolbarItems: tooltip text from label when set; otherwise no tooltip for that item.
  • false → no tooltips anywhere.
isRTLbooleanfalse
  • true → overlay gets RTL mode (dir="rtl" + cv-rtl class).
  • Mirrors nav/button placement, carousel direction/controls, arrow-key mapping, and swipe prev/next mapping.
  • LTR remains default when omitted or false.
  • Details and behavior list: RTL mode (isRTL).
minimizeobject \| boolean{ enabled: false }
  • true (or { enabled: true }) shows a header minimize button.
  • Minimize collapses the shell to a floating restore icon while preserving viewer state.
  • On restore, if the current bound element is hidden/detached, viewer uses a captured snapshot of that item.
  • If another bound element is clicked while minimized, viewer expands and loads that clicked item.
  • Details: Minimize mode.
showCounterbooleantrue
  • true → show "1 / N" (or similar) in the header.
  • false → hide the counter.
preloadAdjacentImagesbooleantrue
  • true → preload previous/next item when they are images (faster navigation).
  • false → disable preloading.
stageOnlyobject \| boolean{ enabled: false, hideNavigation: false }
  • enabled: true → only stage (+ optional prev/next); header and footer hidden.
  • hideNavigation: true → hide arrow buttons (keyboard prev/next still works if keyboardNav is on).
  • Close via Esc or backdrop (when overlayClose).
  • Shorthand: true means { enabled: true }. Details: Stage only.
carouselobject{ enabled: false, navThreshold: 4 }
  • Thumbnail strip under the stage; toggle from header when enabled.
  • See Carousel for all sub-options.
slideshowobject \| nullnull
  • Object with enabled: true → auto-advance between items.
  • Common keys: interval (seconds), autoStart, advanceMedia ('interval' | 'onEnd'), showProgress, hideSlideshowButton.
  • Play/Pause slideshow button in toolbar unless hidden per options.
  • Details: Slideshow.
themestring'dark'
  • Initial look: 'dark' or 'light'.
themeTogglebooleantrue
  • true → header button toggles dark/light.
fullscreenbooleantrue
  • true → header button uses the Fullscreen API on the overlay shell.
  • Independent of video/audio element fullscreen.
  • false → hide the control.
toolbarobject{ download: true, zoom: true, extractText: false, toggleSource: false }
  • download → Download button when a valid URL exists (incl. html with URL).
  • zoom → footer zoom widget for images only.
  • extractText → allow image OCR button when canShowExtractText + extractText are set.
  • toggleSource → when true and resolveMarkdownToggleUrl is set: for type: 'html' items that look like markdown (.md / .markdown via fileExt, title, or src) and load in an iframe, add a View Source / View Markdown toggle that swaps iframe src.
  • inline type always gets Copy (clipboard + "Copied" feedback).
  • More: Toolbar & image zoom.
zoomobject{ min: 1, max: 5, step: 0.01, wheelStep: 0.15, showPercentage: false, onZoom: null, loadHighResUrlAt: false }
  • min / max / step → slider range and step.
  • wheelStep → mouse-wheel zoom step.
  • showPercentage → show e.g. "150%" in the UI.
  • onZoom(zoomLevel, item, viewer) → fired on level change.
  • loadHighResUrlAt → number threshold (e.g. 1.25) or false; above threshold, reload image from zoomUrl / downloadUrl / resolveUrl(..., 'zoomUrl').
  • More: Toolbar & image zoom.
markdownobject{ toggleRawView: false }
  • toggleRawView: true → toolbar toggles rendered Markdown vs raw source.
  • See Markdown.
inlineobject{ syntaxHighlight: false, getLanguage: null }
onInlineHtmlfunctionnull
  • function(content, item, inst) → return HTML for .cv-inline-body.
  • Overrides built-in line numbers / highlighting when provided.
  • See Inline code & highlighting.
toolbarItemsarray[]
  • Extra buttons: objects (id, icon, label, onClick, …), 'separator', or DOM/jQuery nodes.
  • Merged with built-in renderer toolbar.
  • See Toolbar & image zoom.
pdfobject{ workerSrc: null, cMapUrl: null, cMapPacked: true, annotations: true, autoFit: true, autoFitMinScale: 0.75, autoFitMaxScale: 2.5, twoPageView: false, textLayer: true, extractText: false }
  • PDF.js: set workerSrc (and optional cMapUrl, autoFit, spreads, etc.).
  • textLayer → allow selectable text layer when user enables it.
  • extractText: true → show PDF toolbar "Extract text" toggle button.
  • Full table: PDF options.
videoobject{ onGetHdUrl: null, canShowHDButton: null, beforeVideoPlay: null }
  • Applies to the jPlayer video path only (ignored for native <video> fallback).
  • onGetHdUrl(item, viewer) → return HD URL or null.
  • canShowHDButton → optional gate when item.hdUrl exists (show/hide HD control).
  • beforeVideoPlay(item, viewer, next, $stage) → first play: run custom UI or gateContent, then next() so jPlayer starts.
  • Guides: Video HD, Video before play.
supportedVideoFormatsstringnull
  • Comma-separated jPlayer video supply keys (e.g. 'm4v, webmv').
  • null → infer from file extension.
  • See Media (jPlayer).
supportedAudioFormatsstringnull
  • Comma-separated jPlayer audio supply keys (e.g. 'mp3, oga').
  • null → infer from extension.
  • See Media (jPlayer).
itemDatafunctionnull
  • function($el, defaultItem) → return the item object for that element.
  • See Data & callbacks.
wcagbooleanfalse
  • true → focus trap, save/restore focus, dialog ARIA, button labels.
  • See WCAG option.
pollOptionobjectnull
  • With enabled: true, items that have pollOptionLabel show a poll row above the toolbar.
  • See Poll options.
showAttachmentCommentbooleanfalse
  • true + non-empty item.comments → LC-style comment panel on the stage + header toggle.
  • See Attachment comment.
canShowExtractTextfunction | nullnull
  • function(item, viewer) → return true to show image "Extract text" for that item.
  • null → never show (for images).
  • See Image extract-text.
extractTextfunction | nullnull
  • function(item, viewer, doneCallback, errorCallback) on button click.
  • Shows loader until doneCallback(resp) or errorCallback(message).
  • Host runs OCR (or similar); plugin draws word boxes on success.
  • See Image extract-text.

RTL mode (isRTL)

Set isRTL: true to run the overlay in right-to-left mode (default is false for LTR).

When RTL is enabled, the plugin applies these behavior changes:

  • Overlay direction: overlay/shell are rendered with RTL direction (dir="rtl" + RTL class).
  • Navigation layout: prev/next controls and related directional UI are mirrored.
  • Keyboard navigation: arrow mapping is mirrored ( moves next, moves previous).
  • Touch swipe navigation: horizontal swipe prev/next mapping is mirrored.
  • Carousel behavior: strip direction and prev/next carousel control movement are mirrored.
  • Directional tooltips/labels: carousel left/right tooltip/aria labels are adjusted for RTL semantics.

Example:

$('#post').componentViewer({
  isRTL: true,
  toolbar: { download: true, zoom: true }
});

Live demo: see index.html (Case 29 — RTL mode).

Minimize mode

Set minimize: { enabled: true } (or shorthand minimize: true) to enable minimize/restore UI.

  • Minimize: collapses overlay content and shows a floating restore icon.
  • Restore: returns to the active item/session without reopening from scratch.
  • Hidden element fallback: if the active item's bound DOM node is hidden/detached while minimized, restore still renders from a captured snapshot of that item.
  • Click another bound element while minimized: viewer auto-expands and opens the clicked element.
$('#post').componentViewer({
  minimize: { enabled: true },
  carousel: { enabled: true },
  toolbar: { download: true, zoom: true }
});

Live demo: see index.html (Case 30 — Minimize and restore).

PDF options

OptionTypeDefaultDescription
pdf.workerSrcstringnullURL to the PDF.js worker script. Required for PDF.js rendering; if not set and PDF.js is not loaded, the plugin falls back to an iframe.
pdf.cMapUrlstringnullOptional URL for CMap files (e.g. for embedded fonts).
pdf.cMapPackedbooleantrueUse packed CMap format.
pdf.annotationsbooleantrueIf true, PDF annotations (links, highlights, etc.) are rendered.
pdf.autoFitbooleantrueIf true, the page is scaled to fit the stage (width and height), while staying within autoFitMinScale and autoFitMaxScale so the PDF remains readable. If false, fit to width only.
pdf.autoFitMinScalenumber0.75When autoFit is true, scale never goes below this (e.g. 0.75 = 75%) so the PDF stays readable even on large viewports.
pdf.autoFitMaxScalenumber2.5Maximum scale when autoFit is true.
pdf.twoPageViewbooleanfalseWhen true, a toolbar button is shown to toggle between single-page and two-page spread view. The PDF opens in single-page view by default; the user can switch to side-by-side (spread) via the button. Auto-fit scale is computed so both pages fit in the stage width when in two-page mode. Prev/Next and page input work by single page; the current page is the left page of the visible spread or the single page.
pdf.textLayerbooleantrueWhen true, the text layer can be rendered over the PDF when the user turns it on via the Extract text button. The text layer starts inactive; when on, users can select and copy text (e.g. Ctrl/Cmd+C). Set to false to disable text layer rendering. The Extract text button is only shown when pdf.extractText is true (default false).
pdf.extractTextbooleanfalseWhen true, the Extract text button (document-with-lines icon) is shown in the PDF toolbar; clicking it toggles the text layer on or off. When false (default), the button is hidden. Passing e.g. pdf: { extractText: false } leaves all other PDF options at their defaults.
pdf.onPrintfunctionOptional callback when the user clicks the PDF print button. If provided, the default print flow is skipped; the developer can implement custom print (e.g. print all pages, or use the native print dialog on the current view). Signature: onPrint(context) where context has item, pdfDoc, pageNum, totalPages, $canvasWrap, and defaultPrint(). Call context.defaultPrint() to run the built-in behaviour (open a new window with the current page as image and trigger print). If onPrint is not set, the built-in print is used.

PDF zoom. The built-in PDF renderer provides zoom via the toolbar +/− buttons and a zoom preset dropdown (50%, 75%, 100%, 125%, 150%, 175%, 200%, 225%, 250%, and Auto Fit). The footer zoom slider is not shown for PDF items. When the user zooms, all pages (and the text layer) are re-rendered at the new scale, so text selection stays aligned with the visible content.

Page navigation. The current page indicator (e.g. 1 / 14) is click-to-edit: click the current page number, type a page number, then press Enter or blur the field to jump to that page; press Escape to cancel. Scroll-based page detection still updates the indicator when not editing.

PDF.js version compatibility. The plugin uses the core PDF.js API (getDocument, getPage, getViewport, render, getAnnotations) and renders annotations (links, highlights) via a custom overlay. It is compatible with PDF.js 2.2.x (e.g. 2.2.228) as well as 3.x. When pdf.annotations is true, the plugin uses pdfjsLib.Util.normalizeRect when available (e.g. in 3.x); for 2.2.x legacy builds where Util may not be exposed, an internal fallback is used so annotation rendering works without throwing. Render tasks and document loading use .promise when present, with a thenable fallback for older 2.x builds. Set pdf.workerSrc to the worker script that matches your PDF.js build (e.g. pdf.worker.min.js for 2.2.228).

Media (jPlayer)

OptionTypeDefaultDescription
supportedVideoFormatsstringnullComma-separated list of jPlayer format names for video (e.g. 'm4v, webmv'). If null, derived from file extension.
supportedAudioFormatsstringnullComma-separated list of jPlayer format names for audio (e.g. 'mp3, oga'). If null, derived from file extension.

Per-item override: set item.supplied (e.g. via itemData or data-supplied) to override the format for a single item.

Video HD quality

When a video item has an HD or high-quality source URL, you can show an HD button in the player. The user clicks it to switch playback to that source from the current timestamp, so playback continues smoothly without restarting.

Provide the HD URL in either way:

  • item.hdUrl — Set via itemData (e.g. from a data-hd-url attribute). If set and valid, the HD button is shown.
  • video.onGetHdUrl(item, viewer) — Callback that returns the HD URL for the given item, or null. Called when the user clicks HD; if it returns a valid URL, playback switches to that URL from the current position.

When the user clicks HD, the plugin pauses playback, gets the current time, loads the new source via jPlayer setMedia, then seeks to the saved time and resumes if the video was playing. The HD button is highlighted when HD content is playing; clicking it again (or pressing Q) switches back to the original quality. See index.html Case 8b for a working demo.

Video: canShowHDButton and beforeVideoPlay (jPlayer only)

These options apply only when the built-in video renderer uses jPlayer. If jPlayer is not available, the plugin uses a native <video> element instead; canShowHDButton and beforeVideoPlay are not called in that case.

video.canShowHDButton(item, viewer) — Optional. When item.hdUrl is set and passes the plugin’s URL safety check, you can hide or show the HD button based on your own rules (e.g. feature flag, entitlement). If you do not provide this callback, behavior is unchanged: the HD control is shown whenever an HD URL is available via item.hdUrl or onGetHdUrl (see above). The callback is not used when there is no item.hdUrl; in that case HD may still appear when only onGetHdUrl is used.

video.beforeVideoPlay(item, viewer, next, $stage) — Optional. Invoked the first time the user starts playback (play / big play), before jPlayer is initialized. The fourth argument $stage is the jQuery object for the overlay .cv-stage (the same as in onRender). You can append directly to $stage (or to a child such as $stage.find('.cv-video-wrap')) to show any markup or component, then call next() or next({}) when you are ready for jPlayer to start—typically after the user dismisses your UI or after an async check; remove your inserted nodes before calling next() if you do not want them to remain visible.

Alternatively, use the built-in gate (same idea as beforeOpen): next({ gateContent: { html: …, onProceed: function () { return { /* optional context */ }; } } }). The content is shown inside the video wrapper (class cv-video-gate). gateContent.html may be an HTML string, a jQuery collection, or a DOM node; include an element with data-cv-gate-proceed for the continue action. When the user activates it, onProceed runs, its return value is assigned to viewer._videoBeforePlayContext, the gate is removed, and jPlayer starts.

You must call next for playback to begin; if you never call it, the player will not initialize.

Inline code & syntax highlighting

These options apply to type: 'inline' items (source/code view). Content is taken from item.content or fetched from item.src. The built-in view adds line numbers and a Copy button unless you fully override rendering.

OptionTypeDefaultDescription
inline.syntaxHighlightbooleanfalseWhen true, uses window.hljs if present (host must load Highlight.js script and a theme CSS). The plugin uses the v9 API: hljs.highlight(lang, code, ignore_illegals).
inline.getLanguagefunction | nullnullfunction(item) returning a language id string (e.g. 'javascript'). If null, language is inferred from item.fileExt / item.title.
onInlineHtmlfunction | nullnullfunction(content, item, inst) — return HTML for the inline body to replace the default (line numbers + optional Highlight.js). When set, built-in highlighting and layout are skipped for that render.

Data and callbacks

OptionTypeDefaultDescription
itemDatafunctionnullfunction($el, defaultItem) — returns the item object for the given element. Second argument is the item the plugin would build from data-* and DOM; you can add properties to defaultItem and return it, or return a new object. If null, the item is built from data-* and DOM (see Item data).
onDownloadfunctionnullfunction(item, viewer) — called when the user clicks the Download button. If not provided, the plugin uses a default link download.
resolveUrlfunctionnullfunction(item, viewer, urlType) — called before loading a URL. urlType indicates which URL is needed: 'src' (main content), 'zoomUrl' (high-res image when zooming), 'thumbnailUrl' (video poster, carousel thumb). Return the URL string to use; if null/empty, the plugin uses the default for that type (item.src, item.zoomUrl/item.downloadUrl, or item.thumbnailUrl). So you can resolve the correct URL per use (e.g. signed URLs, CDN).
resolveMarkdownToggleUrlfunctionnullfunction(item, viewer, isSource) — used with toolbar.toggleSource for html markdown-like files shown in an iframe. On toggle, the plugin sets the iframe src to the returned string. isSource === true means the user switched to raw/source view; false means back to rendered markdown. Return a non-empty URL; null/empty cancels the toggle (button state unchanged). Initial load still uses resolveUrl / item.src as today.
onRenderfunctionnullfunction(item, $stage, viewer) — if this function appends content to $stage, the built-in renderer for the item type is skipped. May return { toolbar: [...], destroy: function() }.
onToolbarfunctionnullfunction(item, defaultToolbar, viewer) — receives the resolved toolbar array; can modify or replace it. Not used when onRender returns a toolbar.
onErrorfunctionnullfunction(context) — called when a built-in error occurs (e.g. image load failed, PDF failed, fetch failed). context has type (e.g. 'image', 'pdf', 'inline', 'markdown', 'html'), message, item, and $stage. Return true to show your own error UI and skip the default error card; otherwise the default card is shown. If not provided, the plugin shows its built-in error card.
onLoadingfunctionnullfunction(item, viewer) — called just before an item is loaded.
onOpenfunctionnullfunction(item, $stage, viewer) — called after the item is shown and the toolbar is built.
onCompletefunctionnullfunction(item, viewer) — called right after the content is displayed (after transition if any). Similar to Colorbox onComplete.
onCleanupfunctionnullfunction(item, viewer) — called at the start of the close process, before teardown. Similar to Colorbox onCleanup.
onClosefunctionnullfunction(item, viewer) — called when the overlay has closed; item is the one that was visible. Similar to Colorbox onClosed.
beforeOpenfunctionnullfunction(item, element, proceed) — the overlay opens immediately with a circle loader; the footer toolbar and related chrome (nav, counter, carousel toggle, poll row) stay hidden until the real item loads or the user finishes the gate. Your callback runs on the next tick (after open), whether from a click or .componentViewer('open') / .componentViewer('open', index). item / element are as before (element may be empty if items-only and no $el). Call proceed() or proceed({}) to load the attachment; the object is viewer._openContext. Call proceed({ gateContent: { html: '…', onProceed: function() { return { … }; } } }) to show gate HTML in the stage (toolbar still hidden); include data-cv-gate-proceed on a control; on click, onProceed() return value becomes _openContext and the item loads. See Before open & gate content.
beforeCollectItemsfunctionnullRuns before each rebuild of the items list (DOM scan of selector or copy of items): on init, on click-to-open, open, next/prev/goTo, and refresh. Sync: function (viewer) { … } — collection runs immediately after your function returns. Async: function (viewer, proceed) { …; proceed(); } — you must call proceed() when ready (same pattern as beforeOpen). Use this to inject or update .cv-item nodes or viewer.opts.items before the plugin reads them. While the hook runs, viewer._beforeCollectContext is an object with trigger ('init', 'click', 'open', 'next', 'prev', 'goTo', 'refresh'). For 'click', $element is the matched attachment (closest selector to the click) and originalEvent is the native click (originalEvent.target may be a child inside the item). For 'open', openArg is the argument passed to open. It is cleared after collection. If omitted, behavior is unchanged.
onThemeChangefunctionnullfunction(theme, viewer) — called when the user changes the theme via the header toggle (theme is 'dark' or 'light').

Accessibility (WCAG)

OptionTypeDefaultDescription
wcagbooleanfalseIf true, enables focus trap (Tab cycles only inside the overlay), focus save/restore on open/close, initial focus on the close button, and ARIA attributes: dialog role, aria-modal, aria-labelledby/describedby, aria-live on title and counter for dynamic announcements, and aria-label on overlay buttons (close, nav, zoom, theme, fullscreen, carousel toggle and carousel nav). Video and audio control buttons (play, pause, mute, fullscreen, playback speed), carousel item buttons (e.g. “Item 2 of 5”), and PDF toolbar buttons also get aria-label. Set to true for accessibility-conscious deployments.

When the carousel option is set to an object with enabled: true, a thumbnails button appears in the overlay header. Clicking it toggles a strip of thumbnails below the stage so users can jump to any item by clicking its thumbnail. This is useful when there are many attachments and you want a quick overview and navigation.

The strip shows several thumbnails at a time (e.g. 4 or 5 visible). When the number of items exceeds carousel.navThreshold, prev/next arrows appear on the strip to scroll. Video and audio items can show a custom thumbnail via thumbnailUrl (or data-thumbnail) with a play icon overlay; otherwise the filename or type label is shown.

Configuration

OptionTypeDefaultDescription
carouselobject{ enabled: false, navThreshold: 4 }Set to an object to configure the carousel. When carousel.enabled is false, the carousel is disabled (no header button, no strip).
carousel.enabledbooleanfalseWhen true, a button appears in the header; clicking it shows a strip of thumbnails below the stage. Click a thumbnail to go to that item. Video/audio items show thumbnailUrl with a play icon overlay when set; otherwise the filename or type label is shown.
carousel.navThresholdnumber4When the number of items exceeds this value, prev/next buttons appear on the carousel strip to scroll. The strip shows multiple thumbnails at a time; the arrows scroll by a step. Set higher to show arrows only when there are more items (e.g. 6 so arrows appear only when there are more than 6 items).

Behavior

  • The carousel strip is hidden by default when the overlay opens; the user toggles it with the header thumbnails button.
  • When the item count is less than or equal to carousel.navThreshold, the strip prev/next arrows are hidden because all thumbnails fit in view.
  • Clicking a thumbnail scrolls the strip to keep the active item in view and updates the stage to that item.

Example:

$('#post').componentViewer({
  carousel: { enabled: true, navThreshold: 4 },
  toolbar: { download: true, zoom: true }
});

Stage only

When stageOnly.enabled is true, the overlay shows only the center stage (and optionally prev/next navigation). The header (title, counter, close, theme, fullscreen, carousel) and footer (toolbar, zoom) are hidden. The user can close with Escape or by clicking the backdrop (if overlayClose is true). This is useful for kiosk-style or distraction-free viewing.

When stageOnly.hideNavigation is true, the prev/next arrow buttons are also hidden. The user can still move between items using keyboard navigation (Left/Right arrow keys when keyboardNav is true).

Configuration

OptionTypeDefaultDescription
stageOnlyobject \| boolean{ enabled: false, hideNavigation: false }Set to an object to configure. Passing true is treated as { enabled: true }; passing false as { enabled: false }.
stageOnly.enabledbooleanfalseWhen true, only the center stage (and optionally prev/next) is shown; header and footer are hidden.
stageOnly.hideNavigationbooleanfalseWhen true, the prev/next navigation buttons are hidden. Navigation is still possible via keyboard (Left/Right arrows). Only has effect when stageOnly.enabled is true.

Behavior

  • When stageOnly is enabled, the overlay shell gets the class cv-stage-only so that header and footer are hidden via CSS.
  • If slideshow is also enabled and there is more than one item, the footer can still show the Play/Pause slideshow button (see Slideshow).
  • With hideNavigation: true, keyboard prev/next (arrow keys) continue to work when keyboardNav is true.

Example:

$('#post').componentViewer({
  stageOnly: { enabled: true, hideNavigation: false },
  overlayClose: true,
  keyboardNav: true
});

Example with keyboard-only navigation (no prev/next buttons):

$('#post').componentViewer({
  stageOnly: { enabled: true, hideNavigation: true },
  overlayClose: true,
  keyboardNav: true
});

Slideshow

When the slideshow option is set to an object with enabled: true, the viewer can auto-advance to the next item after a fixed interval (or when video/audio playback ends). This is useful for hands-free browsing of multiple attachments. The slideshow only runs when there are at least two items.

A Play slideshow / Pause slideshow button is added to the toolbar when slideshow is enabled, unless hideSlideshowButton: true and autoStart: true (in that case the button is hidden and the slideshow runs automatically with no way to pause from the UI). When autoStart: true and the button is shown, it shows Pause slideshow initially. If autoStart: false, the button shows Play slideshow until the user starts it. Optionally set showProgress: true to display a progress bar in the footer that fills until the next slide (default is false).

Configuration

OptionTypeDefaultDescription
slideshowobject | nullnullSet to an object to enable slideshow. When null or omitted, no auto-advance and no Play/Pause button.
slideshow.enabledbooleanMust be true to enable slideshow (auto-advance and toolbar button).
slideshow.intervalnumber4Seconds to show each item before advancing to the next. Used for all types when advanceMedia is 'interval'; for video/audio with 'onEnd', this is used as a fallback if the media never fires ended.
slideshow.autoStartbooleantrueIf true, the slideshow starts automatically when the overlay opens. If false, the user must click Play slideshow to start.
slideshow.hideSlideshowButtonbooleanfalseWhen true and autoStart is true, the Play/Pause slideshow button is hidden. The slideshow runs automatically with no toolbar control. This option is only considered when autoStart is true.
slideshow.advanceMediastring'interval''interval' — advance after interval seconds for every item (image, PDF, video, etc.). 'onEnd' — for video and audio, advance when playback ends ( ended event); for other types, still use interval. A fallback timer is still used for media in case it never ends (e.g. live stream).
slideshow.showProgressbooleanfalseWhen true, a thin progress bar is shown in the footer that fills over the slide interval to indicate time until the next slide. When false (default), no progress bar is shown.

Note: The option is interval (seconds). There is no delay option (e.g. delay: 4000 is not supported; use interval: 4 for 4 seconds).

Behavior

  • The slideshow timer is cleared when the user closes the overlay, or when they use prev/next/goTo (so manual navigation does not double-advance).
  • When the user clicks Pause slideshow, the timer is cleared and the slideshow does not restart on subsequent item loads until they click Play slideshow.
  • The Play/Pause button appears at the start of the toolbar (before type-specific items such as PDF page controls) and is styled compactly so it does not dominate the footer.

Example:

$('#post').componentViewer({
  slideshow: {
    enabled: true,
    interval: 5,
    autoStart: true,
    advanceMedia: 'interval',
    showProgress: false   // set true to show progress bar until next slide
  },
  toolbar: { download: true, zoom: true }
});

Poll options

When pollOption.enabled is true and an item has pollOptionLabel, a row appears above the toolbar with the label and a radio or checkbox (depending on pollOption.mode). Use this for polls where each option is an image or attachment. Set item.pollOptionSelected to true (e.g. via itemData) to show the option as already selected when the overlay opens; if not given, the option is not selected. pollOption.onSelect(item, selected, viewer, element) is called when the user toggles; selected is the new checked state; element is the DOM node for the .cv-item that produced the item (or null for items-only usage without item.$el). The poll row is hidden for HTML type and for image error (footer is hidden).

Configuration

OptionTypeDefaultDescription
pollOptionobjectnullWhen set, items with pollOptionLabel show a row above the toolbar with the label and a radio or checkbox.
pollOption.enabledbooleanMust be true to enable the poll UI.
pollOption.modestring'radio''radio' for single choice or 'checkbox' for multiple.
pollOption.onSelectfunctionfunction(item, selected, viewer, element)selected is the new checked state (boolean). element is the .cv-item DOM node (or null).

Item fields

FieldSource
pollOptionLabeldata-poll-option-label
pollOptionIddata-poll-option-id
pollOptionSelectedSet via itemData. When true, the option is shown as selected when the overlay opens; if not given, treated as not selected.

Attachment comment

When showAttachmentComment is true and an item has a non-empty item.comments array, a compact dark semi-transparent overlay is shown at the bottom of the stage (over the media), matching the style of LC-Lightbox: each comment can have title (bold), optional “by Author” line, dotted separator, and description text. A header button (comment icon) toggles visibility.

Only item.comments is supported: an array of objects { title?, author?, text }. For a single comment, pass an array with one object: item.comments = [{ title: '...', author: '...', text: '...' }]. Provide it via itemData or data-comments (JSON string). When there is more than one comment, the overlay shows prev/next arrows and a counter (e.g. “Comment 1 of 3”). The “by” label is localized via commentBy; counter and arrow labels use commentCounter, commentPrev, commentNext. When the option is false or item.comments is missing or empty, the toggle and panel are hidden.

Image extract-text (OCR overlay)

When toolbar.extractText is true and both canShowExtractText and extractText callbacks are provided, the plugin shows an "Extract text" toolbar button for image items where canShowExtractText(item, viewer) returns true. (By default toolbar.extractText is false.) Clicking the button calls extractText(item, viewer, doneCallback, errorCallback) and shows a circle loader over the stage. The host performs OCR (e.g. an API call) and invokes doneCallback(resp) on success (loader is removed and the overlay is rendered) or errorCallback(message) on failure (loader is removed and a strip message is shown with the given message).

Options

OptionTypeDefaultDescription
toolbar.extractTextbooleanfalseWhen true, the "Extract text" button can appear for image items (subject to canShowExtractText and extractText). Set to true to enable the feature.
canShowExtractTextfunction | nullnullfunction(item, viewer) — called for each image item when building the toolbar. Return true to show the "Extract text" button; return false (or omit the option) to hide it.
extractTextfunction | nullnullfunction(item, viewer, doneCallback, errorCallback) — called when the user clicks the button. A circle loader is shown. On success call doneCallback(resp); on failure call errorCallback(message) to remove the loader and show message in the strip.

Response shape (resp)

The resp object passed to doneCallback must follow this structure:

{
  data: {
    lines: [
      // Each line is an array of word objects
      [
        { box: [[x0,y0], [x1,y1], [x2,y2], [x3,y3]], word: "Hello" },
        { box: [[x0,y0], [x1,y1], [x2,y2], [x3,y3]], word: "world" }
      ],
      // ... more lines
    ]
  }
}

Each word has a box array of four corner points (typically top-left, top-right, bottom-right, bottom-left) in OCR reference pixel space, and a word string. The plugin maps corners to an axis-aligned rectangle (order-independent) and scales to the displayed <img> (including object-fit: contain letterboxing).

If OCR ran on a larger original than the preview shown in the viewer, include data.imageWidth and data.imageHeight (or sourceWidth / sourceHeight, width / height) matching that coordinate system. If omitted, the plugin assumes coordinates match the image’s naturalWidth / naturalHeight, or infers a wider/taller reference when box coordinates exceed those dimensions.

Behavior

  • When the user clicks "Extract text", a circle loader is shown over the stage until the host calls doneCallback or errorCallback.
  • On success, the loader is removed and the overlay is positioned on top of the image with each word rendered as a highlighted, selectable span.
  • On failure, the host calls errorCallback(message); the plugin removes the loader and shows a strip message with the given message.
  • Clicking "Extract text" again while the overlay is visible removes it (toggle behavior).
  • When the user zooms the image, the overlay is removed. The user can click "Extract text" again to re-fetch at the new zoom level.
  • The overlay uses plugin-scoped CSS classes (.cv-extract-overlay, .cv-extract-layer, .cv-extract-word) and does not depend on any external stylesheet.

I18N

The toolbar button label uses the extractText key from defaultStrings (default: "Extract text"). Override it via $.fn.componentViewer.defaultStrings.extractText for your locale.


Item data

Each item is a plain object describing one attachment. When itemData is not provided, the plugin builds it from the matched element as follows:

FieldSource
typedata-type, or 'markdown' when file extension is .md, or 'image'
srcdata-src or href or first img[src]. For image/video/audio/pdf/inline/markdown: the file URL. For html type: when set, the plugin creates an iframe with this URL (no item.html needed).
titledata-title or title or ''
downloadUrldata-download
zoomUrldata-zoom-url / data-zoomurl or via itemData. For images: high-res URL when zoom.loadHighResUrlAt is set and zoom exceeds that level, and for resolveUrl(..., 'zoomUrl'). Falls back to downloadUrl then src if unset.
fileExtdata-ext
fileSizedata-size
thumbnailUrldata-thumbnail or data-poster
hdUrlSet via itemData (e.g. from data-hd-url). For video: when set to a valid URL, an HD button is shown; clicking it switches playback to this URL from the current timestamp. See Video HD quality.
messagedata-message
htmldata-html (for type html). Used when src is not set.
contentInline content (for type markdown or inline)
authordata-author or set via itemData. General item field (e.g. for use in item.comments entries).
commentdata-comment or set via itemData. General item field; not used by the comment overlay. Use item.comments instead.
commentsArray of { title?, author?, text } set via itemData or data-comments (JSON string). When showAttachmentComment is true and comments is a non-empty array, the overlay shows comments (one at a time if multiple, with prev/next arrows and counter). For one comment, pass [{ title?, author?, text }].
pollOptionLabeldata-poll-option-label
pollOptionIddata-poll-option-id
pollOptionSelectedSet via itemData. When true, the poll option is shown as selected when the overlay opens; if not given, not selected.
supplieddata-supplied (jPlayer format override)

The plugin also sets item.$el to the jQuery-wrapped element. Use itemData to return a custom object: the callback receives ($el, defaultItem); you can add or override properties on defaultItem and return it, or return a new object (e.g. from your API).


Content types

The plugin chooses a renderer in this order:

  1. onRender(item, $stage, viewer) — If it appends to $stage, the built-in renderer is skipped. It may return { toolbar: [...], destroy: function() } to supply a custom toolbar and a cleanup function. See Callbacks (lifecycle) for the full onRender return shape and execution order.
  2. Built-in by type — Based on item.type (default 'image').
  3. Unsupported — If the stage is still empty, a "no preview" card is shown.

Built-in types

TypeDescription
imageImage with zoom slider, mouse wheel zoom, pinch zoom, and drag pan. GIF is supported the same way (use data-type="image" or omit type); the browser displays and animates GIFs in the viewer. If the URL is invalid or the image fails to load, an error card is shown without a download button and the entire toolbar/footer (including poll row) is hidden.
videojPlayer with full controls (or native <video> if jPlayer is not loaded).
audiojPlayer (or native <audio>).
pdfPDF.js with page navigation, thumbnails, zoom (toolbar +/− and zoom preset dropdown including Auto Fit), editable page indicator (click current page to jump), rotate, print, and a text layer toggled by the Extract text toolbar button (active when on; when on, users can select and copy text over the PDF) (or iframe fallback). The footer zoom widget (slider) is not shown for PDF; zoom is via the PDF toolbar only.
inlineSource/code view with line numbers. Content from item.content or fetched from item.src. Toolbar includes a Copy button that copies the file content to the clipboard and shows "Copied to clipboard". Optional Highlight.js via inline.syntaxHighlight and onInlineHtml override — see Inline code & highlighting.
markdownMarkdown rendered as HTML. See Markdown. When markdown.toggleRawView is true, a toolbar button toggles between rendered view and raw/source view.
error"Cannot preview" card with optional custom message and Download button when src or downloadUrl is set.
htmlUser-provided HTML in the stage, or an iframe loaded from item.src. When item.src is set (and passes URL validation), the plugin creates a full-size iframe (cv-html-iframe cv-stage-iframe) and an in-stage loading panel (cv-html-iframe-loader with the same cv-spinner as the overlay loader—similar idea to inline src fetch using cv-inline-loading). The panel is removed on iframe load or error. When item.src is not set, falls back to item.html (string, jQuery object, or DOM node). Header title/counter can be hidden if title is empty. The footer Download button follows toolbar.download and a valid downloadUrl/src like other types.
OtherUnsupported card with file icon, name, optional extension/size, and Download when a URL is available.

Markdown

The markdown type renders Markdown as HTML in the overlay. Use it for .md files or inline markdown content.

Item data

Content can come from:

  • item.content — Inline markdown string (e.g. from data-content).
  • item.src — URL or path to a .md file; the plugin fetches it and renders the response. Relative URLs (e.g. sample.md) are resolved against the current document. Files with .md extension default to type markdown when data-type is not set.

Parser

Include the open-source marked library for full CommonMark support:

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>

If window.marked is not present, the plugin uses a minimal built-in parser (headings, bold, italic, code, links, line breaks).

Toggle raw/source view

Set markdown: { toggleRawView: true } (default false) to show a toolbar button that toggles between rendered Markdown and raw/source view (same line-numbered style as inline content). Useful for viewing the .md source without leaving the overlay. See index.html Case 5b.

Example

<!-- Inline content -->
<div class="cv-item" data-type="markdown" data-title="Note.md" data-content="# Hello\n**Bold** and *italic*.">Note</div>

<!-- Load from URL -->
<div class="cv-item" data-type="markdown" data-title="README.md" data-src="https://example.com/README.md">README</div>

Toolbar & image zoom

Footer toolbar controls (plus the separate image zoom widget) are configured with toolbar, zoom, and optional toolbarItems:

OptionTypeDefaultDescription
toolbar.downloadbooleantrueIf true, the Download button is added when the item has a valid download URL (from itemData), including for html items (minimal footer: slideshow if enabled, plus Download when applicable). Set to false to hide. Hidden for image load errors.
toolbar.zoombooleantrueIf true, the zoom widget (slider and in/out buttons) is shown for image items only. PDF has its own toolbar zoom (+/− and preset dropdown); the footer zoom slider is hidden for PDF.
toolbar.extractTextbooleanfalseIf true, the "Extract text" button is shown for image items when canShowExtractText and extractText callbacks are also provided. See Image extract-text.
toolbarItemsarray[]Array of custom toolbar items (objects, 'separator', or DOM nodes). Merged with the renderer toolbar and the Download button.
zoom.minnumber1Minimum image zoom level.
zoom.maxnumber5Maximum image zoom level.
zoom.stepnumber0.01Step value for the zoom slider.
zoom.wheelStepnumber0.15Zoom increment per mouse wheel step.
zoom.showPercentagebooleanfalseIf true, the zoom widget displays the current zoom as a percentage (e.g. "150%").
zoom.onZoomfunctionnullfunction(zoomLevel, item, viewer) — called when the zoom level changes.
zoom.loadHighResUrlAtnumber | falsefalseWhen set to a number (e.g. 1.25), if the user zooms past that level the image is reloaded from item.zoomUrl, or item.downloadUrl if zoomUrl is missing, or from resolveUrl(item, viewer, 'zoomUrl') when defined. Use for progressive / retina sources. false disables swap.

How the toolbar is resolved

The toolbar is resolved as follows:

  • For html type: minimal toolbar — slideshow button when enabled; optional View Source / View Markdown toggle when toolbar.toggleSource is true, resolveMarkdownToggleUrl is set, and the item looks like markdown (e.g. .md) with iframe src; and Download when toolbar.download is not false and the item has a valid download URL (same rule as other types). Footer hidden if none of these apply (except slideshow progress bar can still keep the footer visible). For image error: no toolbar, footer hidden.
  • When onRender returns a toolbar array: that array is used as-is (no auto download/zoom).
  • Otherwise: renderer toolbar (if any) + toolbarItems (with optional separator) are merged; for inline type a Copy button is added (copies content to clipboard and shows "Copied to clipboard"); for markdown type with markdown.toggleRawView: true a View source / View as Markdown toggle is added; for image type when toolbar.extractText is true and canShowExtractText / extractText are provided, an Extract text button is added; then onToolbar can modify the array; then the Download button is appended when toolbar.download is not false and the item has a valid download URL. The zoom widget is shown for image items when toolbar.zoom is not false.

Ways to build the toolbar

The toolbar array can be built from multiple sources:

SourceDescription
RendererBuilt-in renderers (e.g. PDF) can return a toolbar array (buttons, separators, or DOM nodes).
toolbarItemsOption array merged after the renderer toolbar (with an optional separator before it).
onToolbarCallback receives the merged array and can modify or replace it before rendering.
onRenderIf you return { toolbar: [...] }, that array is used as the full toolbar (no auto download/zoom).
DownloadWhen toolbar.download is true and the item has a valid download URL, a Download button is appended (including for html in the minimal footer).
HTML markdown toggleWhen toolbar.toggleSource is true and resolveMarkdownToggleUrl is provided, html items with a markdown-like extension/path and iframe preview get an icon-only toolbar button (tooltip View Source / View Markdown); cv-active is set while showing the source URL.
Zoom widgetShown for image items when toolbar.zoom is true (separate from the toolbar array).
Extract textWhen toolbar.extractText is true and canShowExtractText / extractText are provided, an Extract text button is added for image items. See Image extract-text.

Toolbar entry types

Each element in a toolbar array can be one of:

TypeSyntaxDescription
Object{ id, icon, label, ... }Rendered as a button. See object properties below.
Separator'separator' or '-'Rendered as a visual separator between buttons.
DOMHTMLElement or jQuery objectAppended as-is (e.g. a span for "Page 1 / 10").

Toolbar item object properties

When an entry is an object, the following properties are supported:

PropertyTypeDefaultDescription
idstringOptional. Adds CSS class cv-tb-id to the button.
iconstringIcon: HTML string (e.g. <svg>...</svg>) or CSS class (e.g. fa fa-share). HTML is sanitized.
labelstringText label; used as tooltip if tooltip is not set.
tooltipstringButton title and, when wcag is true, aria-label. Falls back to label or id.
showLabelbooleanfalseIf true, the label is shown as text beside the icon.
classNamestringExtra CSS class(es) on the button.
shortcutKeystringOptional. Single-character keyboard shortcut (e.g. 'e') to trigger this button. The shortcut is shown in the shortcuts popup (?) only when the button is visible. Reserved keys: Escape, Arrow keys, Space, M, R, Q, D, P, ?, +, -, =.
visibleboolean or functiontrueIf false or a function that returns false, the button is not rendered. Function: visible(item, viewer).
onClickfunctionfunction(item, viewer) — called when the button is clicked.

Example: custom toolbarItems shape

Pass an array of button objects, 'separator' (or '-'), and optionally DOM/jQuery nodes. Each button is a plain object; the plugin merges these entries with the built-in renderer toolbar (PDF controls, etc.) and may append Download after onToolbar runs.

$('#post').componentViewer({
  toolbar: { download: true, zoom: true },
  toolbarItems: [
    {
      id: 'share',
      label: 'Share',
      tooltip: 'Copy link to this attachment',
      // icon: Font Awesome class OR inline SVG (HTML string is sanitized)
      icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.5 2.5 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5z"/></svg>',
      onClick: function (item, viewer) {
        var url = item.downloadUrl || item.src;
        if (url && navigator.clipboard) {
          navigator.clipboard.writeText(url);
          viewer.showStripMessage('Link copied');
        }
      }
    },
    'separator',
    {
      id: 'annotate',
      label: 'Note',
      showLabel: true,
      className: 'my-toolbar-note',
      // Only show for images (optional)
      visible: function (item /* , viewer */) {
        return item.type === 'image';
      },
      // Single letter; avoid reserved keys (Space, M, R, Q, D, P, F, T, C, S, ?, +, -, =, arrows, Esc)
      shortcutKey: 'n',
      onClick: function (item, viewer) {
        /* open your panel, track analytics, etc. */
      }
    }
  ]
});

Minimal variant (icon class + click handler only):

toolbarItems: [
  { id: 'share', icon: 'fa fa-share', label: 'Share', onClick: function (item, viewer) { /* ... */ } },
  'separator',
  { id: 'extra', label: 'Extra', shortcutKey: 'e', onClick: function (item, viewer) { /* ... */ } }
]

Keyboard shortcuts

When keyboardNav is true, the following shortcuts are available. Press ? (Shift+/) to open a popup that lists only the shortcuts enabled for the current item (by type and toolbar options).

KeyAction
EscClose overlay (or close shortcuts popup if it is open).
/ Previous / next item.
+ / -Zoom in / out (image only, when zoom is enabled). PDF zoom uses the PDF toolbar +/− and zoom dropdown.
SpacePlay / Pause (video or audio only when rendered by the plugin; not for custom-rendered content or slideshow).
MMute / Unmute (video or audio only when plugin-rendered).
RCycle playback speed (video or audio only when plugin-rendered; cycles 0.5x → 0.75x → 1x → 1.25x → 1.5x → 2x).
QToggle HD quality (video only when an HD source is available; switches to HD or back to original quality from the current timestamp).
DDownload (when the download button is visible).
PPrint (PDF view only; when the PDF print button is visible).
FToggle fullscreen (when the fullscreen button is visible).
TToggle theme dark/light (when the theme toggle is visible).
CToggle carousel / attachments strip (when carousel is enabled).
SPlay / Pause slideshow (when slideshow is enabled and the slideshow button is visible).
?Show or hide the keyboard shortcuts popup.

Custom toolbar shortcuts: Add shortcutKey: 'e' (or any single character) to a toolbar item to give it a keyboard shortcut. That shortcut appears in the popup only when the button is visible. Reserved keys (Escape, arrows, Space, M, R, Q, D, P, F, T, C, S, ?, +, -, =) are not available for custom items.

Set shortcutsPopup: false to disable the ? popup.


I18N (Internationalization)

All user-facing text in the overlay (button labels, tooltips, error messages, and type labels) comes from a single default string registry defined inside the plugin. The plugin never uses hardcoded strings; it looks up every label by key from this registry. This lets you localize the UI by replacing the registry with your own translations.

For Japanese (日本語) UI, ship or build a copy of the plugin with Japanese defaultStrings (see component-viewer-japanese.js in the repo if present), or set $.fn.componentViewer.defaultStrings to your translations before initializing — same approach as any other locale.

Default strings

The plugin exposes this registry as $.fn.componentViewer.defaultStrings. By default it is the built-in English object used internally. You can:

  • Replace the whole object with your locale (e.g. French, Spanish) so every key uses your text.
  • Override specific keys by assigning a new object that includes all keys you need, or by copying the default and then changing only the keys you care about.

You do not pass strings via component options; there is no strings option. The only way to customize text is to set $.fn.componentViewer.defaultStrings before initializing the plugin (or before opening the overlay).

How to use it for your locale

Use only the keys listed in the Available keys table below. The registry has no duplicate keys: the same key is reused wherever that text appears (e.g. fullscreen for both overlay and video fullscreen button, pdf for PDF label and iframe title, audio for the audio type label). Do not use videoFullscreen, exitVideoFullscreen, typePdf, or typeAudio—those keys were removed; use fullscreen, exitFullscreen, pdf, and audio instead.

  1. After loading the plugin script, set $.fn.componentViewer.defaultStrings to your translation object. Use the same keys as the built-in registry (see Available keys); any missing key falls back to the built-in English value.
  2. Initialize the viewer as usual. All instances will use the strings from defaultStrings.

Example — French (keys from the current registry, no duplicates):

// Replace the entire registry with French
$.fn.componentViewer.defaultStrings = {
  close: 'Fermer',
  fullscreen: 'Plein écran',
  exitFullscreen: 'Quitter le plein écran',
  attachments: 'Pièces jointes',
  showAttachments: 'Afficher les pièces jointes',
  scrollCarouselLeft: 'Défiler le carrousel à gauche',
  scrollCarouselRight: 'Défiler le carrousel à droite',
  previousItem: 'Élément précédent',
  nextItem: 'Élément suivant',
  zoomOut: 'Zoom arrière',
  zoomLevel: 'Niveau de zoom',
  zoomIn: 'Zoom avant',
  switchToLightMode: 'Passer en mode clair',
  switchToDarkMode: 'Passer en mode sombre',
  playSlideshow: 'Lancer le diaporama',
  pauseSlideshow: 'Mettre en pause le diaporama',
  download: 'Télécharger',
  downloadSource: 'Télécharger la source',
  invalidImageUrl: 'URL d\'image invalide ou non sécurisée',
  imageLoadFailed: 'Impossible de charger l\'image',
  play: 'Lecture',
  pause: 'Pause',
  playbackSpeed: 'Vitesse de lecture',
  mute: 'Muet',
  unmute: 'Activer le son',
  thumbnails: 'Miniatures',
  previousPage: 'Page précédente',
  nextPage: 'Page suivante',
  rotate: 'Pivoter',
  print: 'Imprimer',
  pdf: 'PDF',
  previewNotAvailable: 'Aperçu non disponible pour ce fichier',
  file: 'Fichier',
  audio: 'Audio',
  couldNotLoadFileInline: 'Impossible de charger le fichier en ligne',
  noContentInline: 'Pas de contenu ou URL invalide pour la vue en ligne',
  noHtmlProvided: 'Aucun HTML fourni pour la vue HTML',
  typeVideo: 'Vidéo',
  typeCode: 'Code',
  typeHtml: 'HTML',
  typeError: '—'
};

$('#post').componentViewer({ /* options */ });

Example — override only a few keys (merge with default):

// Keep defaults and override only what you need
var defaults = $.fn.componentViewer.defaultStrings;
$.fn.componentViewer.defaultStrings = $.extend({}, defaults, {
  close: 'Cerrar',
  download: 'Descargar',
  fullscreen: 'Pantalla completa'
});
$('#post').componentViewer({});

Available keys

The registry uses the following keys. Your translation object should use these same keys; any key you omit falls back to the built-in English value. The registry has no duplicate keys—the same key is reused wherever that text appears (e.g. fullscreen for both overlay and video fullscreen button).

KeyDefault (English)Used for
closeCloseClose button
fullscreenFullscreenOverlay and video fullscreen button
exitFullscreenExit fullscreenOverlay and video exit-fullscreen button
attachmentsAttachmentsCarousel toggle
showAttachmentsShow attachments
scrollCarouselLeft, scrollCarouselRightScroll carousel left/rightCarousel nav
carouselItemLabelItem %1 of %2 (%1 and %2 replaced with index and total)Carousel item button aria-label when wcag is true
previousItem, nextItemPrevious/Next itemStage nav
zoomOut, zoomLevel, zoomInZoom out / Zoom level / Zoom inZoom widget
switchToLightMode, switchToDarkModeSwitch to light/dark modeTheme toggle
playSlideshow, pauseSlideshowPlay/Pause slideshowSlideshow button
download, downloadSourceDownload / Download sourceDownload button, error card
invalidImageUrl, imageLoadFailedImage error messagesImage error card
play, pause, playbackSpeed, mute, unmuteVideo/audio controlsMedia toolbar
thumbnails, previousPage, nextPage, rotate, print, extractTextPDF toolbar labels; extractText for both the PDF text-layer toggle button and the image OCR overlay button (see Image extract-text)PDF toolbar, image toolbar
pdfPDFPDF iframe title and carousel type label
previewNotAvailable, file, audioUnsupported/error card; audio also for audio fallback title
couldNotLoadFileInline, noContentInline, noHtmlProvidedInline/HTML error messages
typeVideo, typeCode, typeHtml, typeErrorVideo / Code / HTML / —Carousel type labels (PDF and Audio use pdf, audio)
cyclePlaybackSpeedCycle playback speedVideo/audio speed control tooltip
hd, toggleHdHD / Toggle HDVideo HD button
twoPageView, singlePageViewTwo-page view / Single-page viewPDF spread toggle
copy, copiedToClipboardCopy / Copied to clipboardInline type copy button
viewSource, viewMarkdownView source / View as MarkdownMarkdown raw toggle
playPause, muteUnmutePlay / Pause, Mute / UnmuteShortcuts popup labels for media
showShortcuts, keyboardShortcutsShow shortcuts / Keyboard shortcuts? popup
toggleTheme, toggleSlideshowToggle theme / Play · Pause slideshowShortcuts popup
pollUpdatedUpdatedPoll row after selection
toggleComment, commentBy, commentPrev, commentNext, commentCounterComment UI strings (%1 / %2 in counter)Attachment comment overlay

When to set defaultStrings

Set defaultStrings before you call .componentViewer(...) on any element. The plugin reads from it when building the overlay and when rendering labels (e.g. on open, theme toggle, fullscreen toggle). If you change defaultStrings after some viewers are already created, new opens and updated UI will use the new values; already-rendered text in the overlay may not update until the overlay is closed and reopened.


Callbacks (lifecycle)

All callbacks and their option names, types, and defaults are listed in Data and callbacks. Below is a quick reference and the order in which they run.

CallbackWhen
onLoading(item, viewer)Just before the item is loaded.
onOpen(item, $stage, viewer)After the item is shown and the toolbar is built.
onComplete(item, viewer)Right after the content is displayed (after transition if any).
onCleanup(item, viewer)At the start of the close process, before teardown.
onClose(item, viewer)When the overlay has closed; item was the visible one.
onThemeChange(theme, viewer)When the user toggles theme.
onDownload(item, viewer)When the user clicks the Download button (if provided).
onRender(item, $stage, viewer)First chance to render; appending to $stage skips the built-in renderer. May return { toolbar: [...], destroy: function() } — see below.
onToolbar(item, defaultToolbar, viewer)To modify the toolbar before it is rendered. Not used when onRender returns a toolbar.
onError(context)When a built-in error occurs. context has type, message, item, $stage. Return true to show your own error UI; otherwise the default error card is shown.

onRender return value

If onRender returns an object, it can include:

  • toolbar — Array of toolbar item configs (or 'separator'). When provided, this replaces the built-in toolbar for this item; the plugin does not add the default Download or zoom widget. Use this when you render custom content and want full control over the footer.
  • destroy — Optional function() called when the item is unloaded (e.g. on next/prev or close). Use it to tear down custom players, timers, or listeners.

If onRender appends to $stage but does not return an object with toolbar, the plugin still builds the toolbar from the renderer and toolbarItems. For the full option table, see Data and callbacks.

Execution order

When opening or loading an item, lifecycle callbacks run in this order:

  1. onLoading(item, viewer) — before the stage is cleared and content is rendered
  2. Content is rendered (built-in or onRender), toolbar resolved (onToolbar if present)
  3. onOpen(item, $stage, viewer) — after the item is in the stage and toolbar is built
  4. onComplete(item, viewer) — right after content is displayed; if a transition is used (e.g. next/prev with transition), this runs after the transition ends (~320ms)

When closing the overlay:

  1. onCleanup(item, viewer) — at the start of the close process, before the close animation and teardown
  2. Close animation and teardown (~300ms)
  3. onClose(item, viewer) — after the overlay is closed and the instance is cleared

onThemeChange, onDownload, onRender, and onToolbar run when their respective actions occur and are not part of the open/close sequence above. For the complete list of callbacks and their option signatures, see Data and callbacks.


Public API

After initializing with $(container).componentViewer(options), call methods by name:

MethodDescription
$(container).componentViewer('open', index)Opens the overlay at the given index (default 0).
$(container).componentViewer('close')Closes the overlay.
$(container).componentViewer('next')Moves to the next item (respects loop).
$(container).componentViewer('prev')Moves to the previous item (respects loop).
$(container).componentViewer('goTo', index)Moves to the item at index and reloads.
$(container).componentViewer('currentItem')Returns the current item object.
$(container).componentViewer('setTheme', theme)Sets theme to 'dark' or 'light' and updates the UI.
$(container).componentViewer('refresh')Re-collects items and re-binds clicks; if the overlay is open, reloads the current item or closes if there are no items.
$(container).componentViewer('showLoader')Shows the circle loader over the stage. No-op if this instance is not the active viewer.
$(container).componentViewer('hideLoader')Hides the circle loader. No-op if this instance is not the active viewer.
$(container).componentViewer('showStripMessage', text, [durationMs])Shows a strip message inside the overlay (e.g. "Copied", "Saved"). No-op if this instance is not the active viewer. durationMs is optional (default 2000).
$(container).componentViewer('destroy')Removes event handlers and clears data; closes the overlay if this instance is active.

Static API

$.fn.componentViewer.getActive() — returns the currently open ComponentViewer instance, or null if the overlay is closed. Use it when you need the active viewer without a reference to the container (e.g. from a global button or callback). The returned instance supports refresh(), showLoader(), hideLoader(), showStripMessage(text, durationMs), close(), next(), prev(), goTo(index), currentItem(), items, idx, and opts.

var viewer = $.fn.componentViewer.getActive();
if (viewer) {
  viewer.showLoader();
  // ... do async work ...
  viewer.hideLoader();
  viewer.refresh();  // optional: reload current item
}

For cases where you don't have a container element (e.g. opening a chart or an iframe programmatically), use the static method:

$.componentViewer({
  items: [{ type: 'html', title: 'Preview', src: 'https://example.com' }],
  loop: false,
  showCounter: false
}).componentViewer('open', 0);

$.componentViewer(options) creates a temporary container internally, initializes the plugin with the given options, and returns the jQuery wrapper so you can chain .componentViewer('open', index) on it. This is equivalent to:

var $container = $('<div>');
$container.componentViewer(options);
$container.componentViewer('open', 0);

Combine with the items option (array of item objects) to open the viewer without any DOM elements. The items array replaces DOM-based item collection entirely.

Globals: $.fn.componentViewer.defaults (default options), $.fn.componentViewer.Icons (SVG strings for close, prev, next, zoom, download, etc.), $.fn.componentViewer.getActive() (returns the currently open viewer instance or null).


Accessibility

Set wcag: true to enable:

  • Focus trap — Tab and Shift+Tab cycle only inside the overlay.
  • Focus save/restore — Focus is saved when the overlay opens and restored when it closes.
  • Initial focus — Focus moves to the close button when the overlay opens.
  • ARIA — Overlay and shell get appropriate roles and attributes; buttons get aria-label where needed.

When wcag is false, these behaviors are disabled and no dialog ARIA is applied.


Responsiveness & gestures

The overlay is designed to work on desktop and on mobile devices (including in-app web views). The layout is responsive and touch-friendly; gestures are supported on touch devices without affecting desktop behavior.

Responsive UI

  • Full-screen overlay — The overlay fills the viewport so it works on any screen size. Ensure your page uses a viewport meta tag (e.g. <meta name="viewport" content="width=device-width, initial-scale=1.0">) for correct scaling on mobile.
  • Flexible layout — Header, stage, carousel, and footer adapt to available width and height. Buttons and controls are sized for touch when used on small screens.
  • Body scroll lock — When the overlay is open, background page scroll is disabled so the overlay is the only scroll context and gestures are not lost to the page.

Desktop (mouse & keyboard)

  • Navigation — Click prev/next arrows or use Left / Right arrow keys (when keyboardNav is true). No transition animation on click or keyboard.
  • Images — Mouse wheel zooms in/out; drag to pan when zoomed. Zoom slider in the footer adjusts level.
  • Close — Close button, backdrop click (if overlayClose), or Escape.

Mobile / touch / web view (gestures)

On touch devices, the following gestures are supported. They apply only to touch; desktop mouse behavior is unchanged.

GestureActionOption
Swipe left / rightGo to next / previous item. Uses the same transition as the slideshow when navigating.swipeNav: true (default)
Swipe downClose the overlay (when more than one item or when swipe-to-close is allowed).swipeToClose: true (default), overlayClose: true
Pinch (two fingers)Zoom in/out on the current image. Only when viewing an image.Always on for image type
Pan (one finger when zoomed, or two-finger drag)Move the zoomed image within the stage.Always on for image type when zoom > 1

Horizontal swipe is treated as navigation only when the gesture is clearly horizontal (threshold and direction); vertical swipe down is used for close. This avoids conflicts with pinch/pan on images. Single-finger horizontal swipe does not trigger image pan—only prev/next.

To disable touch navigation or swipe-to-close, set swipeNav: false or swipeToClose: false in the options.


Security

The plugin applies several measures to reduce XSS and related risks when rendering user or item data.

MeasureDescription
HTML escapingStrings from item data (e.g. title, fileSize, file name) are escaped when inserted into the DOM so they are never interpreted as HTML. This prevents script injection via malicious titles or metadata.
Safe download filenameThe value used for a.download (suggested file name) is sanitized: control characters and path-unsafe characters (<>:"/\|?* and NUL) are stripped to avoid XSS or path injection if the value is reflected elsewhere.
Resource URL validationURLs used for images, video, audio, PDF, and HTML iframes (src / href) are validated before use. javascript:, vbscript:, and script-capable data: URLs are rejected. Allowed: http://, https://, blob:, protocol-relative (//cdn.example.com/...), relative paths (/connect/viewFile.do, ./file, ../file), and data: only for image/*, video/*, audio/*, and application/pdf.
Download link URL validationURLs used for the Download button (a.href) are validated the same way as resource URLs: http://, https://, blob:, protocol-relative (//...), and relative paths are allowed. javascript:, vbscript:, and data: are rejected.
Toolbar icon sanitizationCustom toolbar icon HTML (toolbarItems[].icon) is sanitized before use: <script> elements are removed, event-handler attributes (e.g. onclick, onload) are removed, and any href / xlink:href that use javascript: or vbscript: are replaced with # to prevent XSS via custom icons.

When you supply HTML via onRender or item.html (HTML type), you are responsible for ensuring that content is safe; the plugin does not sanitize arbitrary HTML content you inject.


Browser support

BrowserMinimum version
Chrome (desktop)87
Firefox (desktop)85
Safari (desktop)14.1
Edge (Chromium)87
Safari (iOS)14.5
Chrome (Android)87
Internet Explorer11 (partial; not recommended)

jQuery 1.7+ is required. jPlayer and PDF.js have their own browser requirements.


Comparison with Colorbox, Lightbox, and LC Lightbox

Colorbox is a popular jQuery lightbox for images and galleries. Lightbox (e.g. Lightbox2) is a classic image lightbox, often vanilla JS. LC Lightbox is a jQuery gallery popup plugin. Below is a side-by-side comparison to help you choose.

Side-by-side comparison

FeatureColorboxLightboxLC LightboxComponentViewer
jQueryYesOptional / noYesYes
ImagesYes, gallery + slideshowYes, galleryYes, galleryYes, gallery + zoom/pan + slideshow
Image zoom/panNo (scale to fit)No (scale to fit)No (scale to fit)Yes (slider, wheel, pinch, pan)
VideoVia iframe/embed onlyVia iframe or not built-inVia iframe or not built-inBuilt-in (jPlayer + native <video>)
AudioVia iframe/embed onlyVia iframe or not built-inVia iframe or not built-inBuilt-in (jPlayer + native <audio>)
PDFVia iframe onlyVia iframe or not built-inVia iframe or not built-inBuilt-in (pdf.js: pages, zoom, thumbnails, annotations)
Other typesInline, iframe, AJAX (generic)Images mainlyImages / gallery focusedInline (code), Markdown, HTML, error/unsupported
ToolbarMinimal (close, arrows/slideshow)Minimal (close, arrows, counter)Minimal (close, arrows, counter)Full: download, zoom, theme, fullscreen, carousel, custom toolbarItems
Custom toolbarNoNoNoYes (custom buttons + shortcutKey)
KeyboardEsc, arrows (if gallery)Esc, arrowsEsc, arrowsEsc, arrows, Space/M/D/F/T/C/S, ?, zoom +/-, custom shortcuts
Shortcuts popupNoNoNoYes (context-aware list)
SlideshowYes (interval, start/stop)No / manualNo / manualYes (interval, autoStart, progress, pause when popup open)
ThemeOne skin (customize via CSS)One skin (customize via CSS)One skin (customize via CSS)Dark/light toggle, theme-aware UI
FullscreenNoNoNoYes (overlay fullscreen)
Carousel / thumbnailsNoNoThumbnails in galleryYes (strip + toggle)
AccessibilityBasic (focus, Esc)Basic (focus, Esc)Basic (focus, Esc)WCAG: focus trap, ARIA, shortcuts popup
CallbacksonOpen, onLoad, onComplete, onCleanup, onClosedFew (e.g. afterChange)FewonOpen, onClose, onLoading, onRender, onToolbar, onDownload, onThemeChange, etc.
Custom renderingLimited (content injection)LimitedLimitedFull: onRender controls content + toolbar
Poll / custom UINoNoNoYes (e.g. poll options above toolbar)

Examples

All examples below can be tried in index.html, which includes full demos for each feature. Use the API buttons at the bottom of that page to open specific cases programmatically.

Basic gallery

$('#gallery').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});

Poll options (radio or checkbox)

Show a poll row above the toolbar for items that have pollOptionLabel. Use onSelect to handle the user's choice. For checkbox (multi-choice), set mode: 'checkbox'. Use pollOptionSelected: true in item data to show an option as already selected when the overlay opens.

$('#post').componentViewer({
  toolbar: { download: true, zoom: true },
  pollOption: {
    enabled: true,
    mode: 'radio',  // or 'checkbox'
    onSelect: function(item, selected, viewer) {
      console.log('Selected:', item.pollOptionLabel, selected);
    }
  },
  itemData: function($el, defaultItem) {
    defaultItem.pollOptionLabel = $el.data('poll-option-label');
    defaultItem.pollOptionId = $el.data('poll-option-id');
    if ($el.data('poll-option-selected')) defaultItem.pollOptionSelected = true;
    return defaultItem;
  }
});

See Case 13 in index.html (radio and checkbox demos).

Attachment comments (single or multiple)

Show a comment overlay on the media. Only item.comments (array) is supported: for one comment use [{ title?, author?, text }]; for multiple, the overlay shows prev/next arrows and a counter.

$('#post').componentViewer({
  showAttachmentComment: true,
  toolbar: { download: true, zoom: true },
  itemData: function($el, defaultItem) {
    // Single comment from data-* attributes
    var t = $el.data('title'), a = $el.data('author'), c = $el.data('comment');
    if (t || a || c) defaultItem.comments = [{ title: t || '', author: a || '', text: c || '' }];
    // Or multiple comments, e.g. from API:
    // if ($el.data('reviews')) defaultItem.comments = $el.data('reviews');
    return defaultItem;
  }
});
// Multiple comments per item
defaultItem.comments = [
  { title: 'Review 1', author: 'Alice', text: 'First comment...' },
  { title: 'Review 2', author: 'Bob', text: 'Second comment...' },
  { text: 'Anonymous note.' }
];

See Case 13b (single comment) and Case 13c (multiple comments) in index.html.

Image extract-text (OCR)

Show an "Extract text" button on image items. Set toolbar.extractText: true and provide the callbacks. The host performs OCR and passes the result to the plugin, which renders a word-level overlay on the image.

$('#gallery').componentViewer({
  toolbar: { download: true, zoom: true, extractText: true },
  canShowExtractText: function(item, viewer) {
    return (item.type || 'image') === 'image';
  },
  extractText: function(item, viewer, doneCallback, errorCallback) {
    // Call your OCR API; on success call doneCallback(resp), on failure call errorCallback(message)
    fetch('/api/getTextFromImage?src=' + encodeURIComponent(item.src))
      .then(function(r) { return r.json(); })
      .then(function(resp) {
        if (resp && resp.data) doneCallback(resp);
        else errorCallback('Could not extract text');
      })
      .catch(function() { errorCallback('Error when fetching text for the image'); });
  }
});

See Image extract-text for the full response shape and behavior details.

Image-only toolbar button

Add a custom toolbar button that appears only for image items, without changing the default toolbar for other types. Use the onToolbar callback: when item.type === 'image', append your button to a copy of the default toolbar and return it. The icon can be an SVG string or a CSS class name (e.g. for an icon font or background image); if it does not start with <, the plugin renders <i class="your-class"></i>.

$('#gallery').componentViewer({
  toolbar: { download: true, zoom: true },
  onToolbar: function (item, defaultToolbar, viewer) {
    if (item.type !== 'image') {
      return defaultToolbar;
    }
    var items = defaultToolbar.slice();
    if (items.length > 0) {
      items.push('separator');
    }
    items.push({
      id: 'my-image-action',
      icon: 'my-icon-class',   // CSS class — plugin renders <i class="my-icon-class"></i>
      label: 'My image action',
      showLabel: false,
      className: 'cv-tb-my-image-action',
      onClick: function (clickedItem, inst) {
        console.log('Image action', clickedItem.src);
      }
    });
    return items;
  }
});

Style the icon in your CSS, e.g. with an icon font or background-image:

.cv-overlay .cv-toolbar .cv-tb-my-image-action i.my-icon-class {
  font-size: 16px;
  /* or: background: url('icon.svg') no-repeat center; width: 16px; height: 16px; */
}

Enable a strip of thumbnails below the stage so users can jump to any item. The carousel toggle in the header shows or hides the strip. Set carousel.enabled: true; the strip appears when the container has more than one item.

$('#post').componentViewer({
  carousel: { enabled: true },
  toolbar: { download: true, zoom: true }
});

See Case 17 (carousel with multiple types) and Case 18 (few items, no scroll arrows) in index.html.

Slideshow

Auto-advance through items with a configurable interval (seconds). Use interval, not delay (there is no delay-in-milliseconds option). Combine with stageOnly for a minimal slideshow view.

$('#post').componentViewer({
  stageOnly: { enabled: true, hideNavigation: false },
  slideshow: { enabled: true, interval: 4 },
  toolbar: { download: true }
});

See Case 20 in index.html.

Video HD quality

Offer a high-quality stream via item.hdUrl or the video.onGetHdUrl callback. The HD button appears in the video toolbar; switching continues playback from the current time.

$('#post').componentViewer({
  video: {
    onGetHdUrl: function(item, viewer) {
      return item.attachmentId ? '/api/hd/' + item.attachmentId : null;
    }
  },
  itemData: function($el, defaultItem) {
    if (defaultItem.type === 'video' && $el.data('hd-url'))
      defaultItem.hdUrl = $el.data('hd-url');
    return defaultItem;
  }
});

See Case 11 (HD video) in index.html.

Video before play and HD button gate (jPlayer)

Gate unsupported or “processing” content before the first jPlayer init, and optionally hide the HD button when item.hdUrl exists but you do not want to offer HD yet.

$('#post').componentViewer({
  video: {
    canShowHDButton: function (item, viewer) {
      // Only when item.hdUrl is set; return false to hide HD despite hdUrl
      return item.allowHd !== false;
    },
    beforeVideoPlay: function (item, viewer, next, $stage) {
      var ext = (item.fileExt || '').toLowerCase();
      if (ext === 'mkv' || ext === 'avi') {
        next({
          gateContent: {
            html: '<div><p>This format may need transcoding. Playback might not work in all browsers.</p>' +
              '<p><button type="button" class="btn" data-cv-gate-proceed>Play anyway</button></p></div>',
            onProceed: function () {
              return { skippedTranscodeWarning: true };
            }
          }
        });
        return;
      }
      next();
    }
  }
});
// After the user proceeds through the gate, optional context:
// viewer._videoBeforePlayContext === { skippedTranscodeWarning: true }

Append directly on the overlay stage (no gateContent):

video: {
  beforeVideoPlay: function (item, viewer, next, $stage) {
    var $banner = $('<div class="my-video-notice"><p>Processing…</p>' +
      '<button type="button" class="btn-my-continue">Continue</button></div>');
    $stage.append($banner);
    $banner.find('.btn-my-continue').on('click', function () {
      $banner.remove();
      next();
    });
  }
}

Note: beforeVideoPlay and canShowHDButton are not used when jPlayer is missing and the native video fallback runs.

Loop disabled, counter hidden

$('#gallery').componentViewer({
  loop: false,
  showCounter: false,
  toolbar: { download: true, zoom: true }
});

See Case 15 (loop: false) and Case 16 (showCounter: false) in index.html.

Custom item data

$('#gallery').componentViewer({
  itemData: function($el, defaultItem) {
    defaultItem.canDelete = $el.data('can-delete');
    defaultItem.attachmentId = $el.data('id');
    return defaultItem;
  },
  toolbar: { download: true }
});

WCAG and custom download

$('#gallery').componentViewer({
  wcag: true,
  onDownload: function(item, viewer) {
    window.location = item.downloadUrl || item.src;
  }
});

Programmatic open

$('#gallery').componentViewer({ toolbar: { download: true } });
$('#gallery').componentViewer('open', 2);  // Open third item

Use the API buttons at the bottom of index.html to open any case by index.

Items array (no DOM elements)

Pass items directly via the items option — no .cv-item elements needed:

$('#container').componentViewer({
  items: [
    { type: 'image', title: 'Photo 1', src: '/images/photo1.jpg', downloadUrl: '/images/photo1.jpg' },
    { type: 'pdf',   title: 'Report',  src: '/docs/report.pdf' },
    { type: 'html',  title: 'Preview', src: 'https://example.com/embed' }
  ],
  loop: false,
  showCounter: true
});
$('#container').componentViewer('open', 0);

Static API (no container needed)

Use $.componentViewer(options) for one-off overlays without a persistent container:

// Open an iframe overlay for a Writer document
$.componentViewer({
  items: [{ type: 'html', title: 'My Document', src: '//writer.zoho.com/writer/zwpreview/abc123' }],
  loop: false,
  showCounter: false
}).componentViewer('open', 0);

// Open a chart using onRender
$.componentViewer({
  items: [{ type: 'custom', title: 'Engagement Graph' }],
  loop: false,
  showCounter: false,
  themeToggle: false,
  onRender: function(item, $stage, inst) {
    var $chart = $('<div id="myChart" style="width:100%;height:100%"></div>');
    $stage.append($chart);
    return {
      destroy: function() {
        var chart = $chart.data('chart');
        if (chart) { chart.destroy(); }
        $chart.remove();
      }
    };
  },
  onOpen: function(item, $stage, inst) {
    renderMyChart('myChart');
  }
}).componentViewer('open', 0);

HTML type with iframe (src)

For the html type, set item.src to a URL and the plugin creates a full-size iframe automatically. While the embed loads, an in-stage panel (cv-html-iframe-loader) shows the same cv-spinner as the overlay loader (same visual language as inline attachments that fetch src with cv-inline-loading). The panel is removed when the iframe fires load or error. The iframe has classes cv-html-iframe and cv-stage-iframe. While loading, the wrapper has cv-html-iframe-loading and the iframe is visually hidden.

$.componentViewer({
  items: [{
    type: 'html',
    title: 'Zoho Sheet',
    src: location.protocol + '//sheet.zoho.com/sheet/preview.do?rid=12345'
  }],
  loop: false,
  showCounter: false
}).componentViewer('open', 0);

When item.src is not set, the plugin falls back to item.html (raw HTML string, jQuery object, or DOM node).

Before open and gate content

Use beforeOpen(item, element, proceed) to run async logic (e.g. an access check) while the viewer is already open: the overlay appears right away with a circle loader and no footer toolbar until proceed runs. The callback is scheduled on the next tick after open, for both clicks and programmatic .componentViewer('open', index) / .componentViewer('open'). For items-only usage, element may be empty if item.$el is not set. Call proceed() or proceed({}) to load the item (options → viewer._openContext), or proceed({ gateContent: … }) to replace the loader with a gate screen in the stage (toolbar stays hidden until the real item loads). Gate HTML must include data-cv-gate-proceed; on click, onProceed() return value becomes _openContext and the item loads. Use resolveUrl to read viewer._openContext for signed URLs or audit flags.

Example: access check and audit gate — The user already sees the overlay with a loader while your API runs. If access is denied but an audit option is allowed, proceed({ gateContent: … }) shows the message and "Show preview"; when clicked, the item loads with a flag for your backend.

$('#gallery').componentViewer({
  beforeOpen: function(item, $el, proceed) {
    var fileId = item.$el.attr('data-file-id') || (item.src && item.src.match(/fileId=(\d+)/) && RegExp.$1);
    if (!fileId) {
      proceed();
      return;
    }
    $.get('/api/canAccessAttachment', { scopeID: scopeID, fileId: fileId })
      .done(function(data) {
        if (data.result === 'success') {
          proceed();
        } else if (data.canShowAuditPopup) {
          var auditHtml = '<div class="gate-message">' +
            '<p>If you preview this file, access will be recorded in audit logs.</p>' +
            '<button type="button" data-cv-gate-proceed>Show preview</button></div>';
          proceed({
            gateContent: {
              html: auditHtml,
              onProceed: function() {
                return { fromManageStorage: true };
              }
            }
          });
        } else {
          alert('You do not have access to this file.');
        }
      })
      .fail(function() {
        alert('Unable to check access.');
      });
  },
  resolveUrl: function(item, viewer, urlType) {
    var url = item.src || (urlType === 'zoomUrl' ? (item.zoomUrl || item.downloadUrl) : null) || '';
    if (viewer._openContext && viewer._openContext.fromManageStorage && url.indexOf('?') !== -1) {
      url += '&fromManageStorage=true';
    } else if (viewer._openContext && viewer._openContext.fromManageStorage) {
      url += (url ? '&' : '?') + 'fromManageStorage=true';
    }
    return url || null;
  }
});

In the example, the gate screen is built as a string; in practice you can clone a template (e.g. from your JSP) and ensure the continue button has data-cv-gate-proceed. The plugin injects the gate HTML into the stage, hides nav/counter, and binds the button. When the user clicks it, onProceed() runs, _openContext is set, and the real item loads; resolveUrl then appends fromManageStorage=true to URLs for that session.


Troubleshooting

Common issues and how to fix them.

Overlay doesn't open when I click an item

  • Selector: Items must match the selector option (default .cv-item). Ensure each clickable element has that class (or your custom selector).
  • Container: The plugin is bound to the container (e.g. $('#my-gallery').componentViewer(...)). Items must be inside that container.
  • Event delegation: Clicks are bound to the container; ensure you're not calling preventDefault() or stopPropagation() on the same click.

PDF doesn't load or shows a blank page

  • PDF.js: Include PDF.js and set pdf.workerSrc to the worker script path (e.g. pdf.worker.min.js). Without it, the plugin falls back to an iframe.
  • CORS: If the PDF is on another origin, the server must send appropriate CORS headers; PDF.js fetches the file via XHR.
  • URL: Use data-src or item.src for the PDF URL; data-type="pdf" and data-ext="PDF" help the plugin detect the type.

Video or audio doesn't play

  • jPlayer: For full controls (play, pause, seek, volume), include jPlayer. Without it, the plugin uses native <video> / <audio>.
  • Formats: Provide a URL the browser supports (e.g. MP4, WebM for video; MP3, OGG for audio). Use data-src or href and data-type="video" or data-type="audio".

Comment or poll doesn't show

  • Comments: Set showAttachmentComment: true and provide item.comments as an array of { title?, author?, text } (e.g. via itemData or data-comments JSON).
  • Poll: Set pollOption: { enabled: true } and give the item pollOptionLabel (and pollOptionId). Use itemData to map from data-poll-option-label etc.

Carousel or slideshow not working

  • Carousel: Set carousel: { enabled: true }. The strip appears only when the container has more than one item.
  • Slideshow: Set slideshow: { enabled: true, interval: 4 } (or other interval in seconds). Use with stageOnly for a minimal slideshow.

ComponentViewer — MIT License. For live demos, open index.html in the plugin folder.

This plugin and its architectural design are by Sankaran N.