Rasterex APINPM Package/docs/components/files/tabs

File Tabs

Keep your application tab UI synchronized with open files inside the Canvas.

Overview

File Tabs allows you to synchronize your host application tab bar with the list of open files inside the viewer.

Canvas manages the active list and selection order. Treat the fileTabs event stream as the single source of truth for rendering your tab headers.

  • Instant Synchronization: Your UI updates dynamically when documents are opened or closed.
  • Two-Way Interaction: Switch active tabs programmatically using the SDK, or let Canvas manage tab changes internally.
  • Detailed Headers: Access document titles, index order, and format icons (PDF, CAD, Image).

Quick Examples

Subscribe to tab changes and switch active documents programmatically:

Switch active tab index

// Switch to the 3rd tab (0-based index)
viewer.documents.setActiveFileByIndex(2);

Listen for tab modifications

const unsubscribe = viewer.documents.on("fileTabs", (event) => {
  console.log("Active file ID:", event.activeId);
  console.log("All open tabs:", event.tabs);
});

Control Flow

Synchronizing tab selections flows through standard SDK callbacks:

Host Sends

1. Host Selects Tab Index

When the user selects a tab header, the host triggers the active file index method.

typescript
viewer.documents.setActiveFileByIndex(2);
Canvas Emits

2. Canvas Returns Tab List

Canvas updates the view, compiles the tab state, and broadcasts the fresh array.

typescript
// Event payload shape
type CanvasFileTabsPayload = {
  activeId: string;
  tabs: Array<{
    id: string;
    title: string;
    index: number;
    icon?: "pdf" | "image" | "cad" | "doc" | "generic";
  }>;
};

Vanilla Integration

Copy these project setup files to configure tab listening, tab rendering, and tab switching handlers:

import { createViewer } from "@rasterex/viewer";
import "./style.css";

const viewer = createViewer({
  container: "#viewer"
});

const tabsEl = document.querySelector("#tabs-container");

function renderTabs(event) {
  if (!tabsEl) return;
  tabsEl.innerHTML = "";

  event.tabs.forEach((tab) => {
    const button = document.createElement("button");
    button.type = "button";
    button.textContent = tab.title;
    button.setAttribute("aria-pressed", String(tab.id === event.activeId));
    
    button.addEventListener("click", () => {
      viewer.documents.setActiveFileByIndex(tab.index);
    });

    tabsEl.appendChild(button);
  });
}

async function startViewer() {
  await viewer.mount();
  await viewer.ready();

  viewer.documents.on("fileTabs", renderTabs);

  // Open multiple files to show tabs
  await viewer.documents.open({
    url: "https://pdfobject.com/pdf/sample.pdf",
    displayName: "sample.pdf"
  });

  await viewer.documents.open({
    url: "https://pdfobject.com/pdf/sample.pdf",
    displayName: "another-file.pdf"
  });
}

startViewer().catch(console.error);
Vanilla Integration

React Integration

Synchronize active files and open lists inside a React custom state bar component:

import { useEffect, useRef, useState } from "react";
import { createViewer, type CanvasFileTab, type RasterexViewer } from "@rasterex/viewer";
import "./style.css";

export function FileTabsExample() {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const viewerRef = useRef<RasterexViewer | null>(null);
  const [tabs, setTabs] = useState<CanvasFileTab[]>([]);
  const [activeId, setActiveId] = useState<string | null>(null);

  useEffect(() => {
    if (!containerRef.current) return undefined;

    const viewer = createViewer({ container: containerRef.current });
    viewerRef.current = viewer;

    const unsubscribe = viewer.documents.on("fileTabs", (event) => {
      setTabs(event.tabs);
      setActiveId(event.activeId);
    });

    async function start(): Promise<void> {
      await viewer.mount();
      await viewer.ready();

      await viewer.documents.open({
        url: "https://pdfobject.com/pdf/sample.pdf",
        displayName: "sample.pdf"
      });

      await viewer.documents.open({
        url: "https://pdfobject.com/pdf/sample.pdf",
        displayName: "another-file.pdf"
      });
    }

    void start().catch(console.error);

    return () => {
      unsubscribe();
      viewer.destroy();
      viewerRef.current = null;
    };
  }, []);

  function selectTab(tab: CanvasFileTab, fallbackIndex: number): void {
    const targetIndex = typeof tab.index === "number" ? tab.index : fallbackIndex;
    viewerRef.current?.documents.setActiveFileByIndex(targetIndex);
  }

  return (
    <div>
      <div id="tabs-container">
        {tabs.map((tab, idx) => (
          <button
            key={tab.id}
            type="button"
            aria-pressed={tab.id === activeId}
            onClick={() => selectTab(tab, idx)}
          >
            {tab.title}
          </button>
        ))}
      </div>
      <div ref={containerRef} style={{ height: 600 }} />
    </div>
  );
}
React Integration

Vue Integration

Synchronize active files and open lists inside a Vue Composition template:

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
import { createViewer, type CanvasFileTab, type RasterexViewer } from "@rasterex/viewer";
import "./style.css";

const containerRef = ref<HTMLElement | null>(null);
const viewerRef = shallowRef<RasterexViewer | null>(null);
const tabs = ref<CanvasFileTab[]>([]);
const activeId = ref<string | null>(null);

let unsubscribe: (() => void) | undefined;

onMounted(async () => {
  if (!containerRef.value) return;

  const viewer = createViewer({ container: containerRef.value });
  viewerRef.value = viewer;

  unsubscribe = viewer.documents.on("fileTabs", (event) => {
    tabs.value = event.tabs;
    activeId.value = event.activeId;
  });

  try {
    await viewer.mount();
    await viewer.ready();

    await viewer.documents.open({
      url: "https://pdfobject.com/pdf/sample.pdf",
      displayName: "sample.pdf"
    });

    await viewer.documents.open({
      url: "https://pdfobject.com/pdf/sample.pdf",
      displayName: "another-file.pdf"
    });
  } catch (error) {
    console.error(error);
  }
});

onBeforeUnmount(() => {
  unsubscribe?.();
  viewerRef.value?.destroy();
  viewerRef.value = null;
});

function selectTab(tab: CanvasFileTab, fallbackIndex: number) {
  const index = typeof tab.index === "number" ? tab.index : fallbackIndex;
  viewerRef.value?.documents.setActiveFileByIndex(index);
}
</script>

<template>
  <div>
    <div id="tabs-container">
      <button
        v-for="(tab, idx) in tabs"
        :key="tab.id"
        type="button"
        :aria-pressed="tab.id === activeId"
        @click="selectTab(tab, idx)"
      >
        {{ tab.title }}
      </button>
    </div>
    <div ref="containerRef" style="height: 600px" />
  </div>
</template>
Vue Integration

Angular Integration

Synchronize active files and open lists inside an Angular component model:

import {
  AfterViewInit,
  Component,
  ElementRef,
  OnDestroy,
  ViewChild
} from "@angular/core";
import { createViewer, type CanvasFileTab, type RasterexViewer } from "@rasterex/viewer";

@Component({
  selector: "app-file-tabs",
  templateUrl: "./file-tabs.component.html"
})
export class FileTabsComponent implements AfterViewInit, OnDestroy {
  @ViewChild("viewerContainer", { static: true })
  viewerContainer!: ElementRef<HTMLElement>;

  tabs: CanvasFileTab[] = [];
  activeId: string | null = null;

  private viewer: RasterexViewer | null = null;
  private unsubscribe?: () => void;

  async ngAfterViewInit(): Promise<void> {
    const viewer = createViewer({
      container: this.viewerContainer.nativeElement
    });

    this.viewer = viewer;

    this.unsubscribe = viewer.documents.on("fileTabs", (event) => {
      this.tabs = event.tabs;
      this.activeId = event.activeId;
    });

    try {
      await viewer.mount();
      await viewer.ready();

      await viewer.documents.open({
        url: "https://pdfobject.com/pdf/sample.pdf",
        displayName: "sample.pdf"
      });

      await viewer.documents.open({
        url: "https://pdfobject.com/pdf/sample.pdf",
        displayName: "another-file.pdf"
      });
    } catch (error) {
      console.error(error);
    }
  }

  selectTab(tab: CanvasFileTab, fallbackIndex: number): void {
    const index = typeof tab.index === "number" ? tab.index : fallbackIndex;
    this.viewer?.documents.setActiveFileByIndex(index);
  }

  ngOnDestroy(): void {
    this.unsubscribe?.();
    this.viewer?.destroy();
  }
}
Angular Integration

Live Preview

Try the interactive preview below to see how events flow between the host and the canvas.

Interactive Workbench

File tabs preview

Open multiple files one at a time and monitor the tabs emitted by the Canvas.

Additional Resources

Keep tab sync connected to file payload references.