jQuery ComponentViewer Plugin Examples

Download This Plugin Back To jQueryScript

A jQuery plugin that opens images, video, audio, PDF, and inline source code in a gallery lightbox with zoom, keyboard navigation, and WCAG support.

documentation.html — API and usage docs.

Case 1 — Built-in Renderers (image, video, audio, pdf)

All types rendered by the plugin. First two images are landscape and portrait — click to see zoom/pan for both orientations. Image gets zoom slider + pan. Video/audio use jPlayer. PDF uses pdf.js with page nav, zoom, rotate, thumbnails. XLSX gets "no preview" card. Custom toolbarItems (Extract, Delete) appear alongside built-in toolbar items.

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

  // Custom buttons shown alongside built-in toolbar items
  toolbarItems: [
    { id: 'extract', icon: '<svg>...</svg>', label: 'Extract Text', shortcutKey: 'e',
      onClick: function(item) { alert('Extract: ' + item.title); } },
    'separator',
    { id: 'delete', icon: '<svg>...</svg>', label: 'Delete',
      onClick: function(item) { confirm('Delete ' + item.title + '?'); } }
  ],

  onDownload: function(item) { /* custom download logic */ },
  onLoading: function(item) { console.log('loading', item.type); },
  onOpen:    function(item) { console.log('opened', item.title); },
  onClose:   function(item) { console.log('closed', item.title); }

  // No onRender → all types use built-in renderers
  // No onToolbar → built-in toolbar used as-is
});
Now
Click any attachment to preview. First: Landscape (wide). Second: Portrait (tall). Third: Mountain (landscape). Then video, audio, PDF, XLSX.
Demo.mp4
Horse.mp3
Spec.pdf
Data.xlsx
Case 1b — Toolbar with custom shortcut keys

Custom toolbar items can define a shortcutKey. When the viewer is open, press that key to trigger the button (e.g. E for Extract, X for Delete). Press ? to open the shortcuts popup — it lists all active shortcuts, including built-in ones (F fullscreen, T theme, C carousel, S slideshow) and your custom keys.

$('#post-toolbar-shortcuts').componentViewer({
  toolbar: { download: true, zoom: true },
  carousel: { enabled: true },
  toolbarItems: [
    { id: 'extract', label: 'Extract Text', shortcutKey: 'e', icon: '...', onClick: function(item) { ... } },
    'separator',
    { id: 'delete', label: 'Delete', shortcutKey: 'x', icon: '...', onClick: function(item) { ... } }
  ]
});
Case 1b
Open an item, then press E (Extract), X (Delete), F (fullscreen), T (theme), C (carousel), S (slideshow), or ? to see all shortcuts.
Case 2 — onToolbar Callback (modify built-in toolbar)

Same built-in renderers, but onToolbar modifies the toolbar per type. Adds a "Share" button to PDF toolbar. Adds "Clip" button to video toolbar. Removes items from image toolbar. All without touching the renderer.

$('#post-ontoolbar').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' },
  toolbarItems: [ TB_EXTRACT, 'separator', TB_DELETE ],

  // Modify built-in toolbar per type — without replacing the renderer
  onToolbar: function(item, defaultToolbar, viewer) {

    if (item.type === 'pdf') {
      // Add Share button to PDF's built-in toolbar
      defaultToolbar.push('separator');
      defaultToolbar.push({ id: 'share', label: 'Share', onClick: fn });
      return defaultToolbar;
    }

    if (item.type === 'video') {
      // Add Clip button to video toolbar
      defaultToolbar.push('separator');
      defaultToolbar.push({ id: 'clip', label: 'Clip', onClick: fn });
      return defaultToolbar;
    }

    if (item.type === 'image') {
      // Remove delete button from image toolbar
      return defaultToolbar.filter(function(tb) {
        return !tb.id || tb.id !== 'delete';
      });
    }

    // return nothing → use default toolbar unchanged
  }
});
1h ago
Same files, but toolbar is customized per type via onToolbar.
Clip.mp4
Report.pdf
Case 3 — onRender Callback (full customer override)

Customer handles video rendering themselves (native <video> instead of jPlayer). PDF is rendered as a simple iframe. Audio falls through to built-in jPlayer. Image falls through to built-in. onRender gets first shot — if it renders, built-in is skipped.

$('#post-onrender').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' },
  toolbarItems: [ TB_DELETE ],

  // Full override — gets first shot before built-in renderers
  onRender: function(item, $stage, viewer) {

    if (item.type === 'video') {
      // Custom native HTML5 video (instead of jPlayer)
      var $v = $('<video controls autoplay>...</video>');
      $stage.append($v);
      return {
        toolbar: [                // ← full replacement, no auto download/zoom
          { id: 'fullscreen', onClick: fn },
          'separator',
          { id: 'download', onClick: fn }
        ],
        destroy: function() { $v[0].pause(); }
      };
    }

    if (item.type === 'pdf') {
      // Custom iframe PDF (instead of pdf.js)
      $stage.append('<iframe src="' + item.src + '"></iframe>');
      return {
        toolbar: [{ id: 'open-tab', onClick: fn }]
      };
    }

    // Don't handle audio/image → falls through to built-in
  }
});
3h ago
Video and PDF use custom rendering. Audio and image use built-in.
Custom Video
Sound.mp3
Custom PDF
Case 4 — Light Theme

Same built-in renderers with theme: 'light'. All components — shell, toolbar, zoom slider, video controls, audio player, PDF viewer, unsupported card — adapt to the light theme.

$('#post-light').componentViewer({
  theme: 'light',
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' },
  toolbarItems: [ TB_EXTRACT ]
});
Just now
Same attachment types, light theme viewer.
Light.mp4
Track.mp3
Memo.pdf
Notes.docx
Case 5 — Markdown Preview

Built-in markdown type renders Markdown as HTML. Content from item.content or fetched from item.src. This page includes marked for full CommonMark support; otherwise a minimal built-in parser is used. Click the note to preview.

$('#post-markdown').componentViewer({
  toolbar: { download: true }
  // Content from data-content; or use data-src to fetch a .md file
});
2h ago
Preview Markdown as HTML in the overlay. First item uses inline data-content; second loads from data-src (URL or path like sample.md).
Inline (data-content)
From URL (data-src)
Case 5b — Markdown with toggle raw/source view

Set markdown: { toggleRawView: true } to show a toolbar button that toggles between rendered Markdown and raw/source view (same line-numbered style as inline). Default is false. Useful for viewing the source of a .md file without leaving the overlay.

$('#post-markdown-toggle').componentViewer({
  toolbar: { download: true },
  markdown: { toggleRawView: true }
});
Case 5b
Open a markdown item. Use the toolbar View source / View as Markdown button to switch between rendered HTML and raw source.
Inline MD (toggle on)
From URL (toggle on)
Case 6 — Custom Supported Formats

Override jPlayer's supplied via supportedVideoFormats and supportedAudioFormats, or per-item via data-supplied. If not provided, auto-detected from file extension.

$('#post-supplied').componentViewer({
  supportedVideoFormats: 'm4v, webmv',   // jPlayer supplied for video
  supportedAudioFormats: 'mp3, oga',    // jPlayer supplied for audio
});

// Per-item override via data attribute (highest priority)
// <div class="cv-item" data-type="video" data-supplied="webmv" ...>

// Priority: data-supplied → supportedVideoFormats/supportedAudioFormats → auto-detect
Just now
Video with global supplied override, and one with per-item override.
Global m4v
Per-item m4v
Auto-detect mp3
Case 7 — Single-Item Viewer (one post, each attachment opens separately)

One post with multiple attachments. Each attachment is wrapped in its own container that has only one .cv-item. The viewer is initialized on each wrapper, so clicking an attachment opens a single-item viewer (no prev/next) for that item only.

// One post; each attachment in a wrapper with exactly one .cv-item
// Init viewer on each wrapper → each opens separately as single-item
$('#post-single .cv-single-item').each(function() {
  $(this).componentViewer({
    selector: '.cv-item',
    toolbar: { download: true, zoom: true },
    pdf: { workerSrc: 'pdf.worker.min.js' }
  });
});
One post, each opens separately
Click any attachment — it opens in its own viewer with only that item (no prev/next).
Single.pdf
Report.pdf
Case 8 — PDF with autoFit

pdf.autoFit: true (default) scales the page to fit the stage (width and height). Resize the window to see it re-fit. Use pdf.autoFitMaxScale to cap the zoom (default 2.5). Set autoFit: false for fit-to-width only.

$('#post-pdf-autofit').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: {
    workerSrc: 'pdf.worker.min.js',
    autoFit: true,           // scale to fit stage (width + height); default true
    autoFitMaxScale: 2.5   // max zoom when autoFit (default 2.5)
  }
});
Now
Click to open — PDF scales to fit the viewer; resize the window to see auto-fit update.
Spec.pdf (autoFit)
Case 8a — PDF two-page view

Set pdf.twoPageView: true to show a toolbar button that toggles single- and two-page view. The PDF opens in single-page view; click the button to switch to side-by-side (spreads). In two-page mode, pages are rendered in pairs (1–2, 3–4, …); the last page appears alone if the total is odd. Auto-fit scales so both pages fit in the stage.

$('#post-pdf-twopage').componentViewer({
  toolbar: { download: true, zoom: true },
  pdf: {
    workerSrc: 'pdf.worker.min.js',
    twoPageView: true   // side-by-side page spreads
  }
});
Now
Click to open — PDF shows two pages side-by-side (spread view).
Spec.pdf (two-page)
Case 8 — Video with custom thumbnail (poster)

Use data-thumbnail or data-poster to pass a thumbnail image URL for video items. The overlay shows this image as the poster until play. If omitted, the default (no poster) is used.

// In HTML: data-thumbnail or data-poster on the video item
<div class="cv-item" data-type="video" data-src="video.mp4"
     data-thumbnail="https://example.com/thumb.jpg" data-title="Demo">
  <img src="https://example.com/thumb.jpg" alt="" />
</div>

// No plugin option needed — thumbnailUrl is read from the element
$('#post-video-thumb').componentViewer({ toolbar: { download: true } });
Now
First: video with data-thumbnail (poster in overlay). Second: same video without thumbnail (default).
No thumbnail
Case 8b — Video with HD quality

When a video item has an HD/high-quality URL (via item.hdUrl in itemData or video.onGetHdUrl callback), an HD button appears in the player. Clicking it switches playback to the HD source from the current timestamp so playback continues smoothly without restarting.

// Option 1: Set item.hdUrl in itemData (e.g. from data-hd-url attribute)
// Option 2: video.onGetHdUrl(item, viewer) returns the HD URL
$('#post-video-hd').componentViewer({
  toolbar: { download: true },
  itemData: function($el, defaultItem) {
    if (defaultItem.type === 'video' && $el.data('hd-url'))
      defaultItem.hdUrl = $el.data('hd-url');
    return defaultItem;
  }
  // Or: video: { onGetHdUrl: function(item, viewer) { return item.attachmentId ? getHdUrl(item.attachmentId) : null; } }
});
Case 8b
Play the video, then click HD in the controls to switch to the high-quality source from the current position.
Demo (HD available)
Case 9 — Native HTML5 & iframe fallbacks (no jPlayer, no pdf.js)

When jPlayer and pdf.js are not loaded, the plugin still previews video, audio, and PDF: video and audio use native HTML5 <video> and <audio> with controls; PDF is shown in an <iframe> (browser’s built-in viewer). To try that, use a minimal page that loads only jQuery + the plugin (omit jPlayer and PDF.js). On this page, jPlayer and PDF.js are loaded, so Case 9 items use the rich players; the same markup would use native/iframe fallbacks without those scripts.

// In your page: load only jQuery + component-viewer.js (no jPlayer, no pdf.js)
// <script src="jquery.min.js"></script>
// <script src="component-viewer.js"></script>
// Video → native <video controls>, Audio → native <audio controls>, PDF → <iframe src="...">

$('#post-no-libs').componentViewer({
  toolbar: { download: true, zoom: true }
});
Fallback demo
On this page, jPlayer and pdf.js are loaded, so these attachments use the rich players. The same items would use native HTML5 and iframe PDF if you initialized the viewer on a page without jPlayer/PDF.js.
Video
Audio
PDF
Case 10 — Inline (source code: js, jsp, java)

Type inline shows file content in the center stage with white background and line numbers. Use item.content (string) or item.src (URL to fetch as text). The toolbar includes a Copy button (inline only): clicking it copies the file content to the clipboard and shows "Copied to clipboard" for 2 seconds. For custom HTML, use onRender: if you append an element to $stage and return, that is shown instead of the built-in viewer.

// item.content = string (pre-loaded) or item.src = URL to fetch
// onRender(item, $stage, viewer): if type === 'inline' and you append HTML to $stage, it replaces built-in
$('#post-inline').componentViewer({
  itemData: function($el) {
    var type = $el.data('type');
    if (type === 'inline')
      return { type: 'inline', title: $el.data('title'), content: INLINE_SNIPPETS[$el.data('key')] };
    // ... default item from $el
  },
  toolbar: { download: true },
  onRender: function(item, $stage, viewer) {
    if (item.type === 'inline' && item.customHtml) {
      $stage.append(item.customHtml); return { toolbar: [] };
    }
  }
});
js, jsp, java
Click to open: item.content (snippets), item.src (fetch from URL), or custom HTML via onRender.
demo.js
Sample.java
From URL
Custom HTML
Case 11 — Error / cannot preview (type "error")

Type error shows the same “cannot preview” container as Data.xlsx in Case 1: file icon, name, optional extension/size, message (default “Preview is not available for this file”), and Download button when item.src or item.downloadUrl is set. Use item.message or data-message to override the text. If onRender appends HTML to $stage for this item, that is shown instead of the default container.

// item: { type: 'error', title?, message?, fileExt?, fileSize?, src?, downloadUrl? } — all from data-* or itemData
$('#post-error').componentViewer({ toolbar: { download: true } });
type "error"
Same template as Data.xlsx: icon, name, “Preview is not available”, Download. No special attributes needed.
Data.xlsx
Case 12 — HTML (type "html")

Type html shows user-provided HTML in the stage. No toolbar, no download. If item.title is not given, the title and counter are hidden. Provide item.html (string, jQuery object, or DOM node); if missing, an error message is shown.

// item: { type: 'html', html: '<div>...</div>' or jQuery/DOM, title?: '' }
$('#post-html').componentViewer({ itemData: function($el) { ... } });
type "html"
Toolbar and download are hidden. With title or no title.
With title
No title
Case 12b — HTML with src (iframe embed, e.g. Zoho WorkDrive)

When type: 'html' and item.src is set (and passes URL checks), the plugin renders a full-stage <iframe> with classes cv-html-iframe and cv-stage-iframe. An in-stage panel (cv-html-iframe-loader) shows the same cv-spinner as the overlay loader (like inline src loading) until the iframe fires load or error. Below: sample WorkDrive embed URL (external; requires network). If the embed blocks framing on your origin, the iframe may show an error page — that still counts as loaded and removes the spinner.

// data-type="html" data-src="https://..." — item is built from DOM; no itemData required
$('#post-html-iframe').componentViewer({
  toolbar: { download: true, zoom: true },
  loop: false
});
WorkDrive embed
Click to open a full-screen iframe preview. In-stage spinner (cv-html-iframe-loader) is removed after the embed finishes loading.
WorkDrive embed
Case 13 — Poll options (option label + radio/checkbox above toolbar)

For polls where each option has an image: set pollOption: { enabled: true, mode: 'radio'|'checkbox', onSelect }. item.title stays the image name (header); item.pollOptionLabel and optional item.pollOptionId are shown in a row above the toolbar with a radio or checkbox. onSelect(item, selected, viewer) is called when the user toggles the option.

$('#post-poll').componentViewer({
  toolbar: { download: true, zoom: true },
  pollOption: {
    enabled: true,
    mode: 'radio',   // or 'checkbox'
    onSelect: function(item, selected, viewer) { /* record vote, etc. */ }
  },
  itemData: function($el) {
    // title = image name; pollOptionLabel / pollOptionId from data-*
    return { type: 'image', title: $el.data('title'), src: ..., pollOptionLabel: $el.data('poll-option-label'), pollOptionId: $el.data('poll-option-id') };
  }
});
Case 13
Click an option image to preview. The option label and a radio appear above the toolbar; use onSelect to perform the action.
Case 13
Same as above but mode: 'checkbox'. You can select multiple options; onSelect(item, selected, viewer) is called for each toggle. Choice 2 is shown as already selected via pollOptionSelected: true (from data-poll-option-selected).
Case 13b — Attachment comment (LC-Lightbox style)

Set showAttachmentComment: true and provide item.comments (array of { title?, author?, text }). For one comment use a single-element array. Example builds comments from data-title/data-author/data-comment in itemData. A dark semi-transparent overlay appears at the bottom of the media; a header button toggles it.

$('#post-comment').componentViewer({
  showAttachmentComment: true,
  toolbar: { download: true, zoom: true },
  itemData: function($el, defaultItem) {
    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 || '' }];
    return defaultItem;
  }
});
Case 13b
Open an attachment. A comment overlay appears at the bottom of the media (title, author, description); use the comment icon in the header to show or hide it. First image also supports multiple comments (see Case 13c).
Case 13c — Multiple comments (JSON array + arrows)

Set showAttachmentComment: true and provide item.comments as an array of { title?, author?, text } (e.g. in itemData). The comment overlay shows one comment at a time with prev/next arrows and a counter (e.g. "Comment 1 of 3").

$('#post-comment-multi').componentViewer({
  showAttachmentComment: true,
  toolbar: { download: true, zoom: true },
  itemData: function($el, defaultItem) {
    if ($el.data('multi-comment')) {
      defaultItem.comments = [
        { title: 'Review 1', author: 'Alice', text: 'First review: Great shot of the landscape.' },
        { title: 'Review 2', author: 'Bob', text: 'Second take: The lighting is perfect here.' },
        { text: 'Anonymous note: Captured in spring 2024.' }
      ];
    }
    return defaultItem;
  }
});
Case 13c
Open the first image. The comment overlay shows three comments; use the arrows in the panel to cycle through them. Second image has a single comment (normal mode).
Case 14 — Image failure (non-previewable)

When an image has an invalid/unsafe URL or fails to load, the viewer shows an error card without a download button, and the toolbar has no download option. First item: invalid URL (not http/https). Second item: valid URL that returns 404 so the image fails to load.

// No special options — built-in image renderer shows error card (no download) when URL is unsafe or load fails
$('#post-image-failure').componentViewer({
  toolbar: { download: true, zoom: true }
});
Case 14
Click to see: invalid URL (error card, no download) and broken image URL (load fails → error card, no download).
Invalid URL
Missing (404)
Case 14b — onError callback (custom error container)

Use onError(context) to show your own error UI when a built-in error occurs (e.g. image load failed, PDF failed). context has type (e.g. 'image', 'pdf'), message, item, and $stage. Return true to skip the default error card; otherwise the plugin shows its built-in card.

$('#post-onerror').componentViewer({
  toolbar: { download: true, zoom: true },
  onError: function(ctx) {
    ctx.$stage.empty().append(
      '<div class="cv-error-card" style="padding:24px;text-align:center;">' +
      '<p style="font-size:15px;margin:0 0 8px;">Custom error: ' + ctx.type + '</p>' +
      '<p style="opacity:.8;font-size:13px;">' + ctx.message + '</p>' +
      '<p style="font-size:12px;opacity:.6;margin-top:12px;">' + (ctx.item.title || '') + '</p>' +
      '</div>'
    );
    return true;  // skip default error card
  }
});
Case 14b
Click an attachment. Errors (invalid URL or 404) trigger onError; we show a custom message and skip the default card.
Invalid URL
Missing (404)
Case 15 — Loop disabled (loop: false)

With loop: false, prev/next do not wrap: on the first item, Previous does nothing; on the last item, Next does nothing. Use this when you want a linear sequence without cycling back to the start or end.

$('#post-loop-false').componentViewer({
  loop: false,
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 15
Click any attachment. Use prev/next — they stop at first and last (no wrap).
Case 16 — Counter hidden (showCounter: false)

With showCounter: false, the header does not show the "1 / N" counter. Use this when you want a cleaner overlay without the item index.

$('#post-counter-hidden').componentViewer({
  showCounter: false,
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 16
Click any attachment. The overlay header has no "1 / 3" counter.
Doc.pdf
Case 17 — Carousel (carousel.enabled: true)

With carousel: { enabled: true }, a button (thumbnails icon) appears in the overlay header. Click it to show a strip of thumbnails below the stage (centered, 4 visible at a time). Use the arrows to scroll; click a thumbnail to go to that item. Video items show data-thumbnail with a play icon. When there are more than 4 items, prev/next buttons appear (carousel.navThreshold: 4).

$('#post-carousel').componentViewer({
  carousel: { enabled: true, navThreshold: 4 },
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 17
Click any attachment, then click the thumbnails button in the header to show the carousel (centered, 4 thumbnails visible). Use the arrows to scroll; video thumb shows a play icon. With 8 items, prev/next arrows appear.
Demo.mp4
Spec.pdf
Case 18 — Carousel, few items (no arrows)

When the number of attachments is less than or equal to carousel.navThreshold, the carousel prev/next arrows are hidden. This example has 5 items with carousel.navThreshold: 6, so no arrows appear — all thumbnails fit in the strip.

$('#post-carousel-few').componentViewer({
  carousel: { enabled: true, navThreshold: 6 },
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 18
5 attachments with carousel.navThreshold: 6. Open the carousel; arrows are hidden because 5 ≤ 6.
Doc.pdf
Clip.mp4
Case 19 — Carousel with all file types

One post with all built-in types: image, video, audio, PDF, inline (code), error (cannot preview), HTML, and unsupported (XLSX). Carousel view is enabled so you can see thumbnails or labels for each type in the strip.

$('#post-carousel-all-types').componentViewer({
  carousel: { enabled: true },
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' },
  itemData: function($el, defaultItem) {
    var t = $el.data('type');
    if (t === 'inline') { defaultItem.type = 'inline'; defaultItem.content = '// Sample code\nfunction hello() { return true; }'; }
    if (t === 'html') { defaultItem.type = 'html'; defaultItem.html = '<p style="padding:16px">Custom HTML content.</p>'; }
    return defaultItem;
  }
});
Case 19
Image, video (with/without thumb), audio, PDF, inline, error, HTML, XLSX. Open any and use the carousel to jump between types.
Demo.mp4
Sound.mp3
Report.pdf
script.js
Missing.file
Note.html
Data.xlsx
NoThumb.mp4
Case 20 — Slideshow with all types

Same set of types as Case 19 with slideshow enabled: auto-advances every 4 seconds (configurable). Use the toolbar "Play slideshow" / "Pause slideshow" to control. slideshow: { enabled: true, interval: 4, autoStart: true, advanceMedia: 'interval' }.

$('#post-slideshow-all-types').componentViewer({
  carousel: { enabled: true },
  slideshow: { enabled: true, interval: 4, autoStart: true, advanceMedia: 'interval' },
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' },
  itemData: function($el, defaultItem) {
    var t = $el.data('type');
    if (t === 'inline') { defaultItem.type = 'inline'; defaultItem.content = '// Sample code\nfunction hello() { return true; }'; }
    if (t === 'html') { defaultItem.type = 'html'; defaultItem.html = '<p style="padding:16px">Custom HTML content.</p>'; }
    return defaultItem;
  }
});
Case 20
Image, video, audio, PDF, inline, error, HTML, XLSX. Opens with slideshow on; advances every 4s. Use Play/Pause slideshow in the toolbar.
Demo.mp4
Sound.mp3
Report.pdf
script.js
Missing.file
Note.html
Data.xlsx
NoThumb.mp4
Case 21 — Slideshow (autoStart: false)

Same as Case 20 but with autoStart: false. The overlay opens with the toolbar showing Play slideshow; the slideshow does not start until you click it. Then it shows Pause slideshow; click again to pause. slideshow: { enabled: true, interval: 4, autoStart: false, advanceMedia: 'interval' }.

$('#post-slideshow-no-autostart').componentViewer({
  carousel: { enabled: true },
  slideshow: { enabled: true, interval: 4, autoStart: false, advanceMedia: 'interval' },
  toolbar: { download: true, zoom: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 21
Opens with Play slideshow; click it to start auto-advance, then Pause slideshow to pause. Same interval (4s) when running.
Case 22 — Stage only (no header, no footer)

With stageOnly: { enabled: true }, the overlay shows only the center stage and prev/next navigation. Header (title, counter, close, theme, fullscreen, carousel) and footer (toolbar, zoom) are hidden. Close with Escape or by clicking the backdrop (if overlayClose: true). You can also pass stageOnly: true as a shorthand for { enabled: true }.

$('#post-stage-only').componentViewer({
  stageOnly: { enabled: true },
  overlayClose: true,
  keyboardNav: true
});
Case 22
Click any image. Only the image and prev/next arrows are shown. Close with Escape or click outside.
Case 23 — Stage only with keyboard-only navigation

Same as Case 22 but with stageOnly: { enabled: true, hideNavigation: true }. The prev/next arrow buttons are hidden; the user moves between images only with keyboard (Left/Right arrow keys). Close with Escape or backdrop click.

$('#post-stage-only-keyboard').componentViewer({
  stageOnly: { enabled: true, hideNavigation: true },
  overlayClose: true,
  keyboardNav: true
});
Case 23
Only the stage is shown; no prev/next buttons. Use Left / Right arrow keys to move. Close with Escape or click outside.
Case 24 — Slideshow with hidden Play/Pause button (stage only)

Combines stageOnly: { enabled: true, hideNavigation: true } with slideshow: { enabled: true, autoStart: true, hideSlideshowButton: true }. All UI is hidden: header, footer, and prev/next buttons. The overlay shows only the stage; items auto-advance every 4 seconds. Use keyboard (Left/Right) to move or Escape to close. No Play/Pause button — close the overlay to stop the slideshow.

$('#post-slideshow-hide-btn').componentViewer({
  stageOnly: { enabled: true, hideNavigation: true },
  slideshow: { enabled: true, interval: 4, autoStart: true, hideSlideshowButton: true, advanceMedia: 'interval' },
  overlayClose: true,
  keyboardNav: true
});
Case 24
Opens in stage-only mode with no header, footer, or nav buttons. Auto-advances every 4s. Use Left/Right to move, Escape or click outside to close.
Case 25 — WCAG (accessibility)

With wcag: true, the viewer enables accessibility behavior: 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, and aria-label on buttons). Use Tab to move between controls; focus returns to the trigger when you close. Inspect the overlay buttons in DevTools to see aria-label on close, attachments, fullscreen, theme, prev/next, zoom, etc.

$('#post-wcag').componentViewer({
  wcag: true,
  toolbar: { download: true, zoom: true },
  carousel: { enabled: true },
  pdf: { workerSrc: 'pdf.worker.min.js' }
});
Case 25
Click any attachment. Tab through the overlay controls; focus is trapped inside. Close and focus returns to the trigger. Buttons have aria-label for screen readers.
Spec.pdf
Case 26 — canShowTooltip: false (no hover tooltips)

With canShowTooltip: false, the viewer does not show any hover tooltips on header/footer/toolbar buttons. Buttons behave the same; only the custom tooltip popup is disabled. Compare with other cases where hovering a button shows a tooltip.

$('#post-no-tooltip').componentViewer({
  canShowTooltip: false,
  toolbar: { download: true, zoom: true },
  carousel: { enabled: true }
});
Case 26
Click any attachment. Hover over close, fullscreen, theme, carousel, prev/next, zoom, or download — no tooltip appears. All other behavior is unchanged.
Case 27 — GIF image

GIF files are rendered as image type (use data-type="image" or omit type). The built-in image renderer uses <img src="...">, so the browser displays and animates the GIF in the viewer with the same zoom and pan behavior as other images.

$('#post-gif').componentViewer({
  toolbar: { download: true, zoom: true },
  carousel: { enabled: true }
});
// GIF uses type "image" — no special config needed
Case 27
Click an attachment to open the viewer. GIFs animate in the overlay; zoom and pan work as with other images.
Case 28 — Slideshow with progress bar (showProgress: true)

Same as Case 21 (slideshow, manual start) but with showProgress: true. A thin progress bar appears in the footer and fills over the slide interval to show time until the next slide. Use Play slideshow to start; the bar animates each 4 seconds. slideshow: { enabled: true, interval: 4, autoStart: false, showProgress: true }.

$('#post-slideshow-progress').componentViewer({
  carousel: { enabled: true },
  slideshow: { enabled: true, interval: 4, autoStart: false, showProgress: true, advanceMedia: 'interval' },
  toolbar: { download: true, zoom: true }
});
Case 28
Click any image. Click Play slideshow to start; a progress bar in the footer fills until the next slide (4s). Pause to stop the bar.
Case 29 — RTL mode (isRTL: true)

Sets isRTL: true to render the overlay in RTL mode. This mirrors navigation placement, carousel controls/direction, and keyboard/swipe prev-next mapping while keeping the same item data flow.

$('#post-rtl').componentViewer({
  isRTL: true,
  carousel: { enabled: true },
  toolbar: { download: true, zoom: true }
});
Case 29
Open any item and verify RTL behavior for arrows, swipe, carousel, and tooltips.
Case 30 — Minimize and restore

Enable minimize: { enabled: true } to show a header minimize button. Minimizing collapses the viewer to a floating restore icon. Click the icon to restore the current item. If the bound element becomes hidden while minimized, restore still shows the captured item snapshot. If you click another attachment while minimized, the viewer expands and loads that clicked item.

$('#post-minimize').componentViewer({
  minimize: { enabled: true },
  carousel: { enabled: true },
  toolbar: { download: true, zoom: true }
});
Case 30
Open an item, click minimize, then either restore via the floating button or click another attachment directly. Use the "Toggle 2nd item visibility" button to test hidden-element restore fallback.
Programmatic API
How It All Fits Together
// Renderer priority:
//   1. onRender(item, $stage, viewer) — customer full override (first shot)
//   2. Built-in renderer (image/video/audio/pdf/inline/error/html)
//   3. Unsupported "no preview" card
//
// Toolbar priority:
//   onRender returns { toolbar } → full replacement (no auto download/zoom)
//   Built-in renderer toolbar + toolbarItems + download + zoom(image only)
//     → passed through onToolbar(item, toolbar, viewer) for modification
//
// What each type shows (built-in mode):
//   image → [toolbarItems] + zoom slider + download    (zoom/pan built-in)
//   video → jPlayer in stage, [toolbarItems] + download
//   audio → jPlayer in stage, [toolbarItems] + download
//   pdf   → pdf.js in stage, [thumbs|◁|page|▷|zoom±|rotate|print] + [toolbarItems] + download
//   inline → white bg + line numbers (item.content or item.src), [toolbarItems] + download
//   error  → cannot-preview card (same as unsupported: icon, name, message, Download); onRender can override
//   html   → user-provided HTML only; no toolbar, no download; title/counter hidden if no title
//   other → "no preview" card, [toolbarItems] + download
//   pollOption → when enabled and item.pollOptionLabel, row above toolbar with option label + radio/checkbox; onSelect(item, selected, viewer)
Toolbar Builder Reference

A toolbar is an array of items. Each item can be an object, a separator string, or a raw DOM element.

// ─── Toolbar Item Schema ─────────────────────────────────
{
  id:        'download',               // unique id → CSS class cv-tb-download
  icon:      '<svg>...</svg>',          // HTML string or CSS class name
  label:     'Download',                // tooltip text
  showLabel: false,                     // if true, label shows as text beside icon
  className: 'my-custom-class',         // extra CSS class on the button
  visible:   true,                      // boolean or function(item, viewer)
  onClick:   function(item, viewer) {}  // click handler
}

// ─── Separator ───────────────────────────────────────────
'separator'    // or '-'

// ─── Raw DOM Element ─────────────────────────────────────
$('<span class="page-label">Page 1</span>')[0]

// ─── Conditional Visibility ──────────────────────────────
{
  id: 'extract',
  visible: function(item, viewer) {
    return item.type === 'image' || item.type === 'pdf';
  },
  onClick: function(item) { ... }
}

// ─── Icon as CSS class (Font Awesome, etc.) ──────────────
{ id: 'share', icon: 'fa-solid fa-share-nodes', label: 'Share' }

// ─── Icon as SVG HTML string ─────────────────────────────
{ id: 'zoom', icon: '<svg width="18" height="18" ...>...</svg>' }

// ─── Button with visible label text ──────────────────────
{ id: 'save', icon: 'fa-solid fa-floppy-disk', label: 'Save', showLabel: true }

// ─── Full Example: building a toolbar array ──────────────
var myToolbar = [
  { id: 'prev-page', icon: '<svg>◁</svg>', label: 'Prev',
    onClick: function() { goToPrevPage(); } },

  $('<span>Page 1 / 10</span>')[0],    // raw DOM element

  { id: 'next-page', icon: '<svg>▷</svg>', label: 'Next',
    onClick: function() { goToNextPage(); } },

  'separator',

  { id: 'print', icon: 'fa-solid fa-print', label: 'Print',
    visible: function(item) { return item.type === 'pdf'; },
    onClick: function() { window.print(); } },

  { id: 'download', icon: $.fn.componentViewer.Icons.download,
    label: 'Download',
    onClick: function(item) { /* download logic */ } }
];

// ─── Where toolbars are used ─────────────────────────────

// 1. Default custom items (shown alongside built-in zoom/download)
toolbarItems: myToolbar

// 2. Returned from onRender (full replacement, no auto download/zoom)
onRender: function(item, $stage, viewer) {
  return { toolbar: myToolbar };
}

// 3. Returned from built-in renderers (PDF page nav, etc.)
//    → merged with toolbarItems + auto download
//    → passed through onToolbar for modification

// 4. Modified via onToolbar
onToolbar: function(item, defaultToolbar, viewer) {
  defaultToolbar.push('separator');
  defaultToolbar.push({ id: 'share', onClick: fn });
  return defaultToolbar;
}
Supported Formats Resolution
// Priority order:
//   1. data-supplied attribute on the element (per-item)
//   2. supportedVideoFormats / supportedAudioFormats (per-post init)
//   3. Auto-detect from file extension
//
// Extension → jPlayer format mapping:
//   mp4/m4v → m4v    webm → webmv    ogv → ogv    flv → flv
//   mp3 → mp3    m4a → m4a    ogg/oga → oga    wav → wav
//
// Examples:

// Separate formats for video and audio
$('#post').componentViewer({
  supportedVideoFormats: 'm4v, webmv',
  supportedAudioFormats: 'mp3, oga'
});

// Per-item override via data attribute (highest priority)
// <div class="cv-item" data-type="video" data-supplied="webmv" data-src="clip.webm">

// Auto-detect (default — no override needed)
// <div class="cv-item" data-type="video" data-src="clip.mp4">  → supplied: 'm4v'
// <div class="cv-item" data-type="audio" data-src="song.mp3">  → supplied: 'mp3'