Gallery index.html Tabbed Interface Architecture Explained

The gallery tabbed interface in cathrynlavery/diagram-design implements a three-layer architecture separating presentation CSS, a centralized JavaScript state object, and reusable event handlers to manage diagram type selection, variant switching, and accessible keyboard navigation.

The repository cathrynlavery/diagram-design provides a lightweight, framework-free solution for browsing diagram variations through an interactive gallery. The core implementation resides in skills/diagram-design/assets/index.html, where vanilla JavaScript handles complex UI state management, ARIA accessibility, and responsive layout through a clean separation of concerns.

The Three-Layer Architecture

The tabbed interface is organized into distinct layers that handle specific responsibilities:

  • Presentation Layer: CSS rules defined in the <style> block (lines 11-78) control the visual appearance of .tab elements, the .topbar container, and the responsive behavior of the preview iframe.

  • State Management Layer: A global state object declared at lines 5-6 tracks the currently selected diagram type and visual variant.

  • Interaction Logic Layer: The bindTabs() and update() functions (lines 9-38 and 40-82) handle event binding, state updates, DOM synchronization, and accessibility attribute management.

State Management and the Update Cycle

The interface relies on a mutable state object that serves as the single source of truth for the current view configuration.

The state is initialized with default values:

const state = { type: "architecture", variant: "" };

When users interact with the interface, the update() function (lines 9-38) executes the following synchronization steps:

  1. Identifies the active type button and checks for the data-single attribute to determine if variant selection should be disabled.
  2. Toggles the active class and updates aria-checked attributes on both type and variant tabs.
  3. Constructs the preview URL using the pattern example-${state.type}${state.variant}.html.
  4. Sets the <iframe> element's src attribute and updates the "open raw" link to point to the constructed URL.
  5. Updates aria-labelledby on the iframe to reference the currently selected tabs for screen reader context.

Tab Layout and Accessibility Structure

The DOM structure implements the ARIA radio group pattern to ensure full accessibility for assistive technologies.

Two distinct tab groups are rendered:

  • Type tabs: A <div id="type-tabs"> container holding buttons with data-type attributes (e.g., "architecture", "flowchart"). The first button receives class="tab active" on initialization.
  • Variant tabs: A <div id="variant-tabs"> container with buttons defining data-variant attributes including empty string "", "-dark", and "-full".

The bindTabs() function dynamically assigns role="radio" to each tab button and role="radiogroup" to the containers. Each tab receives aria-controls="preview" to establish a relationship with the iframe element. Disabled states are applied both visually and via the disabled property when single-variant types are selected.

Event Binding and Keyboard Navigation

The bindTabs(containerId, key) function (lines 40-82) provides a reusable abstraction for connecting DOM elements to the state management system.

This function implements several critical features:

  • Programmatic ID assignment: Generates unique identifiers for each tab to support precise ARIA labeling.
  • Activation closure: The inner activate() function updates state[key] with the selected value, invokes update() to refresh the UI, and manages focus states.
  • Input handling: Registers listeners for both click events and keydown events to support ArrowRight, ArrowLeft, Home, and End key navigation.
  • Boundary management: Keyboard navigation wraps logically at the first and last enabled tabs within each group.

The function is instantiated twice during initialization: once for the type tabs with key="type" and once for variant tabs with key="variant".

Styling and Responsive Behavior

The presentation layer uses standard CSS with specific considerations for mobile accessibility.

Key styling rules include:

  • Flexbox-based layout for the .topbar containing the tab groups.
  • Visual distinction for .tab.active states using border and background color changes.
  • Media queries (lines 66-76) that enable horizontal scrolling for the type tab row on narrow viewports while maintaining touch target sizes.

The iframe element occupies the remaining viewport height below the topbar, providing a seamless preview of the selected diagram file.

Programmatic Interaction Examples

Developers can manipulate the gallery state directly through the global state object and update() function.

To switch diagram types programmatically:

// Change to flowchart type and refresh the preview
state.type = "flowchart";
update();  // Loads example-flowchart.html in the iframe

To simulate selecting a single-variant tab that disables other options:

// Activate the "Import · draw.io" tab which uses data-single
document.querySelector('[data-type="import-drawio"]').click();
// Automatically clears state.variant and disables variant tabs

To test keyboard navigation programmatically:

// Focus first variant and emulate right arrow key
const firstVariant = document.querySelector('#variant-tabs .tab');
firstVariant.focus();
const event = new KeyboardEvent('keydown', { key: 'ArrowRight' });
firstVariant.dispatchEvent(event);
// Advances to the next variant and triggers update()

Summary

  • The gallery interface in skills/diagram-design/assets/index.html separates concerns into presentation, state management, and interaction layers for maintainability.
  • The global state object tracks type and variant selections, with the update() function synchronizing DOM elements, iframe sources, and ARIA attributes.
  • bindTabs() provides reusable, accessible tab functionality including full keyboard navigation (Arrow keys, Home/End) and ARIA radio group semantics.
  • CSS media queries ensure the interface remains functional on mobile devices while preserving accessibility requirements for touch targets and screen readers.
  • Diagram previews follow the naming convention example-{type}{variant}.html, enabling straightforward extension for new diagram categories.

Frequently Asked Questions

Where is the tabbed interface logic implemented in the repository?

The core logic resides in skills/diagram-design/assets/index.html within the cathrynlavery/diagram-design repository. This single file contains the HTML structure, CSS styling (lines 11-78), and JavaScript functions including bindTabs() and update() that power the interactive gallery.

How does the interface communicate the current state to assistive technologies?

The implementation uses ARIA radio group patterns: tab containers receive role="radiogroup" while individual buttons get role="radio" and aria-checked attributes that reflect the active state. The preview iframe uses aria-labelledby to reference the selected tabs, providing context about which diagram variant is currently displayed.

What happens when a user selects a diagram type marked as single-variant?

When a tab with the data-single attribute is activated, the update() function automatically clears state.variant, disables all variant tab buttons via the disabled property, and updates their aria-checked status. This prevents users from selecting incompatible visual variants for diagram types that only support one presentation mode.

Yes, the bindTabs() function explicitly handles keyboard events including ArrowRight, ArrowLeft, Home, and End keys. Focus management moves between enabled tabs only, wrapping at the ends of the tab list, and pressing Space or Enter activates the focused tab—ensuring full WCAG-compliant keyboard accessibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →