Section States & Styling

The booking renderer tracks four states for each section outline: highlighted, selected, unavailable, and filtered. Each state can be styled independently using the svgSectionStyles theme, and toggled programmatically through the renderer API. States work consistently across all outline types – SVG backgrounds, editor-created shapes, auto-generated outlines, and fallback outlines.

Section states

Every section outline can have zero or more of these states active simultaneously:

State Trigger Typical use
highlighted Mouse hover or programmatic Visual feedback on hover
selected User click on GA section Section added to cart
unavailable disableSections() Sold out, restricted, or closed sections
filtered filterSections() Show only a subset of sections (e.g., price tier)

States are stored as data-* attributes on SVG outline elements (data-highlighted, data-selected, data-unavailable, data-filtered) and styled via CSS generated from your theme configuration.

Styling with svgSectionStyles

Pass a svgSectionStyles object inside theme when creating the renderer. Each key corresponds to a state, and each value controls the visual properties for that state.

import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';

const renderer = new SeatmapBookingRenderer(
  document.getElementById('seatmap'),
  {
    publicKey: 'your-public-key',
    theme: {
      svgSectionStyles: {
        default: {
          bgColor: 'rgba(200, 200, 200, 0.2)',
          stroke: { color: '#888', width: '2', opacity: 1 },
          cursor: 'pointer',
        },
        hovered: {
          bgColor: 'rgba(33, 150, 243, 0.5)',
          stroke: { color: '#1565C0', width: '3', opacity: 1 },
          cursor: 'pointer',
        },
        selected: {
          bgColor: 'rgba(76, 175, 80, 0.6)',
          stroke: { color: '#2E7D32', width: '3', opacity: 1 },
          cursor: 'pointer',
        },
        unavailable: {
          bgColor: 'rgba(244, 67, 54, 0.4)',
          stroke: { color: '#C62828', width: '3', opacity: 1 },
          cursor: 'not-allowed',
          opacity: 0.5,
        },
        filtered: {
          bgColor: 'rgba(0, 0, 0, 0.15)',
          stroke: { color: '#999', width: '1', opacity: 0.5 },
          cursor: 'default',
          opacity: 0.3,
        },
      },
    },
  }
);
renderer.loadEvent('your-event-id');

Style properties reference

Each state accepts these properties:

Property Type Description
bgColor string Fill color of the outline. Use rgba() for semi-transparent overlays on top of the venue background.
stroke.color string Outline border color.
stroke.width string Outline border width (e.g., '2').
stroke.opacity number Outline border opacity (0 to 1).
sectionName.color string Color of the section label text inside the outline.
cursor string CSS cursor when hovering the section (e.g., 'pointer', 'not-allowed').
opacity number Overall opacity of the outline element (0 to 1). Defaults: 0.5 for unavailable, 0.3 for filtered. Theme values override the defaults.

The default state accepts all properties listed above. Other states (hovered, selected, unavailable, filtered) additionally support bgColor for the fill overlay.

OutlineStates interface

The renderer tracks section state using the OutlineStates interface. Each field is an optional boolean – only set the fields you want to change.

interface OutlineStates {
  highlighted?: boolean;   // Mouse hover or programmatic highlight
  selected?: boolean;      // Section added to cart (GA sections)
  unavailable?: boolean;   // Disabled -- cannot interact
  filtered?: boolean;      // Dimmed by active filter
}

When reading state back, all four fields are always present:

interface IEntityStates {
  highlighted: boolean;
  selected: boolean;
  unavailable: boolean;
  filtered: boolean;
}

API reference

Disabling sections

Mark sections as unavailable to prevent interaction. Disabled sections show the unavailable style and ignore clicks.

// Disable specific sections by ID
renderer.disableSections([101, 102, 103]);

// Disable with reset -- re-enable all previously disabled, then disable these
// Useful for category buttons: each click disables a new set without accumulating
renderer.disableSections([201, 202], { resetAll: true });

// Re-enable specific sections
renderer.enableSections([101, 102, 103]);

You can also disable by section name:

renderer.disableSectionsByNames(['Floor A', 'Floor B']);
renderer.enableSectionsByNames(['Floor A']);

Filtering sections

Filtering shows only the sections you specify, dimming all others. This is useful for price tier selection, accessibility filtering, or category views.

// Show only these sections -- all others get the "filtered" style
const premiumIds = [101, 102, 103];
renderer.filterSections(premiumIds);

// Remove all filters -- restore all sections to normal
renderer.removeFilterSections();

The filter logic inverts the IDs you pass: sections in the array remain normal, sections not in the array get the filtered state.

Querying sections

// Get all sections with their current state
const sections = renderer.getSections();
sections.forEach(section => {
  console.log(section.id, section.name, section.isGa, section.disabled, section.filtered);
});

Full method list

Method Description
disableSections(ids, options?) Disable sections by numeric IDs. Pass { resetAll: true } to re-enable all before disabling.
enableSections(ids) Re-enable previously disabled sections.
disableSectionsByNames(names, options?) Disable sections by name string.
enableSectionsByNames(names) Re-enable sections by name string.
filterSections(ids, options?) Show only specified sections; dim all others.
removeFilterSections(ids?) Remove filter from specific sections, or all if no IDs passed.
getSections() Returns all sections with current state (id, name, isGa, disabled, filtered).
setOutlineStates(id, states) Low-level: set specific states on a section. Pass null to clear. Pass undefined as id to apply to all.
getOutlineStates(id) Low-level: read current state of a section. Returns all four boolean fields.
onSectionStateChange(callback) Register a callback fired when any section’s state changes. Receives the section ID.

Migration from legacy method names

The previous *SvgSections* method names are deprecated but still work. Update when convenient:

Deprecated Replacement
disableSvgSectionsByIds() disableSections()
enableSvgSectionsByIds() enableSections()
disableSvgSectionsByNames() disableSectionsByNames()
enableSvgSectionsByNames() enableSectionsByNames()
filterSvgSectionsByIds() filterSections()
removeFilterSvgSectionsByIds() removeFilterSections()

The new names reflect that these methods work identically across all section types, not just SVG-bound sections.

When calling deprecated methods, the renderer logs a one-time console warning with the recommended replacement. To suppress these warnings during migration:

const renderer = new SeatmapBookingRenderer(element, {
  publicKey: 'your-public-key',
  suppressDeprecationWarnings: true,
});

Low-level state API

For advanced use cases – custom UI frameworks, external state synchronization, or applying multiple states simultaneously – use the low-level state API directly.

// Set multiple states on a single section
renderer.setOutlineStates(101, {
  highlighted: true,
  unavailable: true,
});

// Read current state
const state = renderer.getOutlineStates(101);
// Returns: { highlighted: true, selected: false, unavailable: true, filtered: false }

// Clear all states on a section
renderer.setOutlineStates(101, null);

// Clear all states on all sections (pass undefined as id)
renderer.setOutlineStates(undefined, null);

The low-level API sets states directly without side effects (no price recalculation, no data model updates). Use the high-level methods (disableSections, filterSections) for standard flows that also update the data model.

State change callback

Register a callback to be notified when any section’s state changes. This is useful for keeping an external UI (sidebar, legend, tooltip) in sync with renderer state.

renderer.onSectionStateChange((sectionId) => {
  const state = renderer.getOutlineStates(sectionId);
  updateSidebar(sectionId, state);
});

The callback fires for all state changes – hover, selection, disable, filter, and programmatic updates.

The resetAll option

Both disableSections and filterSections accept an optional { resetAll: true } parameter. When set, the renderer first clears all previously applied states of that type before applying the new ones.

This is useful for exclusive selection patterns like category filter buttons:

// Category filter buttons -- each click shows only that category
document.getElementById('btn-vip').addEventListener('click', () => {
  renderer.filterSections(vipSectionIds, { resetAll: true });
});

document.getElementById('btn-standard').addEventListener('click', () => {
  renderer.filterSections(standardSectionIds, { resetAll: true });
});

document.getElementById('btn-all').addEventListener('click', () => {
  renderer.removeFilterSections();
});

Without resetAll, you would need to call removeFilterSections() before each filterSections() call, which can cause a visible flicker.

Section hover and selection

Hover highlighting and section selection are enabled through renderer settings:

const renderer = new SeatmapBookingRenderer(
  document.getElementById('seatmap'),
  {
    publicKey: 'your-public-key',
    highlightSectionOnHover: true,
    enableSectionSelection: true,
    onSectionSelect: (section) => {
      console.log('Selected:', section.id, section.name);
      return true; // return true to confirm selection
    },
    onSectionDeselect: (section) => {
      console.log('Deselected:', section.id, section.name);
      return true;
    },
    onSectionMouseEnter: (section) => {
      // Update external UI (tooltip, sidebar, etc.)
    },
    onSectionMouseLeave: () => {
      // Clear external UI
    },
  }
);

When highlightSectionOnHover is true, hovering a section applies the hovered style. When enableSectionSelection is true, clicking a GA section toggles the selected style and fires the select/deselect callbacks.

State combinations

Multiple states can be active on the same section. The renderer applies CSS with specificity rules:

Combination Visual result
selected + hover Thicker stroke, full opacity
unavailable + hover Slightly increased opacity (still shows unavailable)
selected + unavailable Shows at reduced opacity (unavailable takes precedence visually)

Outline types

The renderer creates section outlines from multiple sources. All four types respond to states and styling identically:

Source Origin Attribute
SVG background Floor plan SVG with section bindings data-outline-source="svg"
Shape Editor-created rectangles, polygons, paths data-outline-source="shape"
Auto Editor-generated outlines from seat groups data-outline-source="auto"
Fallback Runtime-generated from seat positions data-outline-source="fallback"

You do not need to handle these types differently. All public API methods work uniformly across all types. The data-outline-source attribute is an internal detail exposed only for debugging.

Outline visibility during animation

During pan and zoom animations, the outline SVG layer is hidden by default for performance. The outlines reappear after the animation completes. To keep outlines visible during animations (at a performance cost), set:

const renderer = new SeatmapBookingRenderer(element, {
  publicKey: 'your-public-key',
  showOutlineLayerOnAnimation: true,
});

Complete example

This example creates a renderer with styled states, disables sold-out sections, and filters to a specific price tier on user action:

import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';

const renderer = new SeatmapBookingRenderer(
  document.getElementById('seatmap'),
  {
    publicKey: 'your-public-key',
    highlightSectionOnHover: true,
    enableSectionSelection: true,
    theme: {
      svgSectionStyles: {
        default: {
          bgColor: 'rgba(100, 100, 100, 0.1)',
          stroke: { color: '#666', width: '1', opacity: 0.8 },
          cursor: 'pointer',
        },
        hovered: {
          bgColor: 'rgba(33, 150, 243, 0.4)',
          stroke: { color: '#1976D2', width: '2', opacity: 1 },
        },
        selected: {
          bgColor: 'rgba(76, 175, 80, 0.5)',
          stroke: { color: '#388E3C', width: '2', opacity: 1 },
        },
        unavailable: {
          bgColor: 'rgba(158, 158, 158, 0.3)',
          stroke: { color: '#9E9E9E', width: '1', opacity: 0.5 },
          cursor: 'not-allowed',
          opacity: 0.4,
        },
        filtered: {
          bgColor: 'rgba(0, 0, 0, 0.08)',
          stroke: { color: '#ccc', width: '1', opacity: 0.3 },
          cursor: 'default',
          opacity: 0.2,
        },
      },
    },
    onSectionSelect: (section) => {
      console.log('Added to cart:', section.name);
      return true;
    },
    onSectionDeselect: (section) => {
      console.log('Removed from cart:', section.name);
      return true;
    },
  }
);

renderer.loadEvent('your-event-id').then(() => {
  // Disable sold-out sections after event loads
  const soldOutIds = [301, 302];
  renderer.disableSections(soldOutIds);
});

// Filter to a price tier when user clicks a button
document.getElementById('filter-premium').addEventListener('click', () => {
  const premiumIds = [101, 102, 103];
  renderer.filterSections(premiumIds);
});

document.getElementById('clear-filter').addEventListener('click', () => {
  renderer.removeFilterSections();
});

Playground

Use the interactive playground to test all section states in real time. Load the unifiedSectionStates preset at /playground/?preset=unifiedSectionStates to see:

  • Styled outlines across all outline types (SVG, shape, fallback)
  • Buttons for disable, enable, filter, unfilter, select, and reset
  • DOM inspector showing live data-* attributes, computed styles, and cursor values
  • Console logging for all section events