Wireframe Demonstration System#
The wireframe demonstration system provides interactive UI mockups throughout the jdaviz documentation. This page describes the architecture, usage, and customization options for developers.
Overview#
The wireframe system consists of three modular components:
wireframe-base.html- HTML structurewireframe-demo.css- Styling and themingwireframe-controller.js- Interactive behavior and automation
These components are loaded via the wireframe-demo Sphinx directive, which automatically injects them into documentation pages with full configuration support.
Component Files#
wireframe-base.html#
Contains the complete HTML structure for the interactive wireframe, including:
Wireframe container and toolbar with icon buttons
Sidebar panel with tabs and content areas
Viewer area with data visualization mockup
Data menu popup
Cycle control button for demonstrations
wireframe-demo.css#
Contains all CSS styles for the wireframe, including:
Layout and positioning (flexbox-based)
Color schemes and theming (dark/light mode support)
Responsive design with media queries
Smooth animations and transitions
Component-specific styles for toolbar, sidebars, viewer, expansion panels
Special styling for plugins sidebar with accordion UI
Key Features:
Uses
:has()selector for conditional styling (e.g., removing padding when expansion panels are present)CSS variables for easy theme customization
Smooth transitions for panel expansions (0.3s ease)
Hover states and interactive feedback
wireframe-controller.js#
Contains all JavaScript functionality using ES5 syntax:
Auto-cycling - Demonstrates sidebars in sequence with configurable timing
Sidebar management - Dynamically generates content from registry or custom sources
Expansion panels - Accordion-style panels for plugins sidebar (5 panels)
Demo actions - Supports actions like
open-panel,select-data,select-tabTiming control - Custom per-step delays using
@delaysyntaxRepeat control - Demos can loop continuously or stop after one cycle
API snippets - Toggleable code examples for each feature
Interactive controls - Pause/resume, manual sidebar selection
Usage#
Basic Directive#
To embed a wireframe in any RST file, use the wireframe-demo directive:
.. wireframe-demo::
This creates a default wireframe with standard auto-cycling behavior.
Configuration Options#
The directive supports extensive customization through options:
demo#
Type: string
Default: 'loaders,save,settings,info,plugins,subsets'
Defines the demo sequence - which sidebars to show and what actions to perform.
Simple sidebar list:
.. wireframe-demo::
:demo: plugins,subsets,info
Actions with timing:
.. wireframe-demo::
:demo: plugins,plugins@1000:open-panel,plugins:select-data=Image 2
Action Syntax:
sidebar- Show the sidebarsidebar:action- Perform an action on the sidebarsidebar:action=value- Perform an action with a parametersidebar@duration:action- Specify how long this step lasts before proceeding (in milliseconds)sidebar@duration!:action- Same as above but skip highlighting the affected element:actionor:action=value- Standalone action (no sidebar required)
The ! suffix after the duration disables the highlight animation for that step.
This is useful when you want to set initial state without drawing attention to the change:
# Normal: shows highlight on the color button
settings@1500:set-color=#00FF00
# No highlight: sets color quietly without visual emphasis
settings@0!:set-color=#FF0000
Available Actions:
open-panel- Opens the expansion panel in plugins sidebarselect-tab=<name>- Switches to a specific tab in multi-tab sidebarsselect-dropdown=<label>:<value>- Selects a dropdown value (case-insensitive matching)click-button=<text>- Clicks a button by its text content (case-insensitive)api-toggle- Toggles API mode on/offopen-data-menu- Opens the data menu popup (standalone action)highlight=<selector>- Highlights element(s) matching CSS selector (standalone action)
enable-only#
Type: string (comma-separated)
Default: All sidebars enabled
Restricts which toolbar buttons can be clicked by users. Other buttons appear disabled.
.. wireframe-demo::
:enable-only: plugins
:demo: plugins
To disable all sidebar buttons (e.g., for standalone action demos):
.. wireframe-demo::
:enable-only:
:demo: open-data-menu
initial#
Type: string (comma-separated)
Default: First sidebar in demo sequence
Sets which sidebar(s) are visible when the wireframe first loads, before the demo starts.
.. wireframe-demo::
:initial: loaders,plugins
:demo: save,settings
This is useful to show a specific starting state that differs from the demo sequence.
show-scroll-to#
Type: boolean
Default: false
Controls visibility of “Learn more” scroll-to buttons in sidebar descriptions.
.. wireframe-demo::
:show-scroll-to: true
demo-repeat#
Type: boolean
Default: true
Controls whether the demo loops continuously or stops after one cycle.
.. wireframe-demo::
:demo-repeat: false
When set to false, the demo plays once and shows a restart button.
plugin-name#
Type: string
Default: 'Data Analysis Plugin'
Sets the name of the plugin in the expansion panel header.
.. wireframe-demo::
:plugin-name: Aperture Photometry
plugin-panel-opened#
Type: boolean
Default: true
Controls whether the plugin expansion panel is open by default.
.. wireframe-demo::
:plugin-panel-opened: false
custom-content#
Type: string
Default: Auto-generated from registry
Provides custom HTML content for sidebars. Overrides the default content from the registry.
Format: sidebar=content or sidebar:tab=content
.. wireframe-demo::
:custom-content: plugins=<div class="wireframe-description">Custom content</div>
Complete Example#
Here’s a complete example from a plugin documentation page:
.. _plugins-aperture_photometry:
********************
Aperture Photometry
********************
.. wireframe-demo::
:demo: plugins,plugins@1000:open-panel,plugins:select-dropdown=Data:Image 2,plugins@3000:highlight=.wireframe-form-group:has(#data-select)
:enable-only: plugins
:plugin-name: Aperture Photometry
:plugin-panel-opened: false
:demo-repeat: false
.. plugin-availability::
This plugin performs aperture photometry...
This configuration:
Shows only the plugins sidebar
After 1 second, opens the expansion panel
Selects “Image 2” from the Data dropdown
After 3 seconds, highlights the Data dropdown group
Only allows clicking on the plugins button
Names the panel “Aperture Photometry”
Panel starts closed
Demo runs once and stops (highlight persists since it’s the last step)
Advanced Demo Actions#
select-dropdown#
Syntax: sidebar:select-dropdown=<label>:<value>
Selects a value from a dropdown menu. Both label and value matching are case-insensitive.
.. wireframe-demo::
:demo: loaders,loaders:select-dropdown=Source:file,loaders:select-dropdown=Format:1D Spectrum
The action will:
Find dropdowns by their label text (case-insensitive)
Match the value against option text (case-insensitive)
Set the selected value
Trigger a change event
Example: select-dropdown=data:image 2 matches label “Data” and selects option “Image 2”
highlight#
Syntax: sidebar@duration:highlight=<selector> or :highlight=<selector>
Highlights one or more elements using a CSS selector. This is a standalone action that doesn’t require a sidebar.
.. wireframe-demo::
:demo: loaders,loaders:select-tab=Data,loaders@3000:highlight=#source-select
:demo-repeat: false
The highlight:
Uses an animated orange pulsing glow effect
Lasts for the step’s duration (the
@durationvalue specifies how long to wait before proceeding)Clears when moving to the next step
Persists if it’s the last step and
demo-repeat: falseCan target multiple elements with a single selector
Common selectors:
#element-id- Highlight by ID.class-name- Highlight by classselect[name="source"]- Highlight specific form element.wireframe-form-group:has(#data-select)- Highlight parent container
api-toggle#
Syntax: sidebar:api-toggle
Toggles the API mode on or off for the current sidebar view.
.. wireframe-demo::
:demo: loaders,loaders@2000:api-toggle
Plot Options Actions#
The settings sidebar with Plot Options tab supports special actions for controlling the Plot Options UI elements.
select-viewer#
Syntax: settings:select-viewer=<viewerId>
Selects a viewer in the Plot Options viewer dropdown and updates the layer tabs to show layers from that viewer.
.. wireframe-demo::
:demo: settings,settings:select-viewer=imageviewer
:demo-repeat: false
select-layer#
Syntax: settings:select-layer=<index>
Selects a layer tab by its index (0-based). Updates the color button to show that layer’s color.
.. wireframe-demo::
:demo: settings,settings:select-layer=0,settings@1000:select-layer=1
:demo-repeat: false
set-color#
Syntax: settings:set-color=<color>
Sets the color of the currently selected layer. The color can be any valid CSS color (hex, rgb, named colors).
.. wireframe-demo::
:demo: settings,settings:set-color=#FF0000,settings@1500:set-color=#00FF00
:demo-repeat: false
Complete Plot Options example:
.. wireframe-demo::
:initial: viewer-legend@0:default:Image|Catalog
:demo: settings,settings:select-viewer=default,settings:select-layer=1,settings@0:set-color=#FF0000,settings@1500:set-color=#00FF00
:demo-repeat: false
This demonstrates:
Opening the settings sidebar (Plot Options tab)
Selecting the “default” viewer
Selecting layer B (index 1)
Setting color to red immediately
After 1.5 seconds, changing color to green
Standalone Actions#
Some actions can be used without activating a sidebar first:
pause- Waits without performing any actionopen-data-menu- Opens data menu popuphighlight=<selector>- Highlights elements
pause#
Syntax: pause@duration
Pauses the demo for the specified duration without performing any action. Useful for adding delays between actions or giving the user time to observe the current state.
.. wireframe-demo::
:demo: loaders,pause@3000,settings
:demo-repeat: false
Use these with :enable-only: to create focused demos:
.. wireframe-demo::
:demo: open-data-menu,highlight=#data-format-select
:enable-only:
:demo-repeat: false
Multi-Viewer Actions#
The wireframe supports dynamic multi-viewer layouts through special viewer actions.
These actions can be used in both :initial: and :demo: options.
Viewer Action Syntax#
Viewer actions use the format: viewer-action@duration:param1:param2:param3
The @duration specifies how long (in milliseconds) to wait after performing this action before proceeding to the next step. Use @0 for immediate transitions.
Available viewer actions:
viewer-add#
Syntax: viewer-add@duration:direction:newId or viewer-add@duration:direction:newId:parentId
Splits an existing viewer and adds a new one.
Parameters:
direction- Split direction:horiz,h,vert,v,horiz-before,hb,vert-before,vbnewId- Unique identifier for the new viewerparentId(optional) - ID of viewer to split. Defaults to the last added viewer.
.. wireframe-demo::
:demo: viewer-add@1000:horiz:spectrum,viewer-add@1000:vert:cube:default
This creates:
Splits horizontally, adds “spectrum” viewer on the right
Splits the “default” viewer vertically, adds “cube” viewer below it
viewer-image#
Syntax: viewer-image@duration:viewerId:imagePath
Sets a background image for a viewer.
Parameters:
viewerId- ID of the target viewerimagePath- Path to the image (relative to _static or absolute URL)
.. wireframe-demo::
:initial: viewer-image@0:default:cosmic_cliffs.png
:demo: loaders
viewer-legend#
Syntax: viewer-legend@duration:viewerId:layer1|layer2|layer3
Sets the legend layers displayed in a viewer. Layers are pipe-separated (|).
Parameters:
viewerId- ID of the target viewerlayers- Pipe-separated list of layer names
.. wireframe-demo::
:initial: viewer-legend@0:default:MIRI Image|Subset 1
:demo: plugins
Layer icons are automatically assigned based on layer name:
Names containing “spectrum”, “1d”, “2d” get spectrum icon
Names containing “image”, “miri”, “nircam” get image icon
Names containing “cube”, “3d” get cube icon
Names containing “subset” get subset icon
viewer-focus#
Syntax: viewer-focus@duration:viewerId
Visually emphasizes a viewer with a highlighted border.
.. wireframe-demo::
:demo: viewer-add@1000:horiz:spectrum,viewer-focus@500:spectrum
viewer-remove#
Syntax: viewer-remove@duration:viewerId
Removes a viewer and collapses the split container if only one viewer remains.
.. wireframe-demo::
:demo: viewer-add@1000:horiz:spectrum,viewer-remove@2000:spectrum
viewer-tool-toggle#
Syntax: viewer-tool-toggle@duration:viewerId:toolName
Activates a tool in the viewer’s toolbar, showing it as selected.
Parameters:
viewerId- ID of the viewer to modifytoolName- Name of the tool to activate. Available tools:home- Home/reset viewpanzoom(orpan-zoom,pan_zoom) - Pan and zoom toolrectroi(orrect-roi,rectangle) - Rectangular ROI/subset toolcircroi(orcirc-roi,circle,subset) - Circular ROI/subset tool
.. wireframe-demo::
:demo: viewer-tool-toggle@1000:default:panzoom,viewer-tool-toggle@1500:default:circroi
:demo-repeat: false
Complete Multi-Viewer Example#
Here’s a complete example showing a multi-viewer demo:
.. wireframe-demo::
:initial: viewer-image@0:default:cosmic_cliffs.png,viewer-legend@0:default:MIRI Image|Subset 1
:demo: viewer-add@2000:horiz:spectrum,viewer-legend@0:spectrum:1D Spectrum|Subset 1,viewer-focus@500:spectrum,plugins
:demo-repeat: false
This configuration:
Initial state: Sets cosmic_cliffs.png as background for default viewer with two legend layers
Demo step 1: After 2 seconds, splits horizontally and adds “spectrum” viewer
Demo step 2: Immediately sets legend layers for spectrum viewer
Demo step 3: After 500ms, focuses the spectrum viewer
Demo step 4: Shows the plugins sidebar
Layout Examples#
Side-by-side viewers (1x2):
:demo: viewer-add@1000:horiz:right
Stacked viewers (2x1):
:demo: viewer-add@1000:vert:bottom
2x2 grid:
:demo: viewer-add@500:horiz:right,viewer-add@500:vert:bottom-left:default,viewer-add@500:vert:bottom-right:right
L-shaped layout:
:demo: viewer-add@500:horiz:right,viewer-add@500:vert:bottom:default
Using Viewer Actions in index.html#
For the landing page (index.html), which doesn’t use the Sphinx directive, configure
viewer actions via window.wireframeConfig:
window.wireframeConfig = {
showScrollTo: true,
initialState: [
"viewer-add@0:horiz:imageviewer",
"viewer-image@0:imageviewer:_static/cosmic_cliffs.png",
"viewer-legend@0:imageviewer:MIRI Image|Subset 1"
],
customDemo: [
"viewer-add@2000:horiz:spectrum",
"viewer-legend@0:spectrum:1D Spectrum",
"loaders"
],
demoRepeat: true
};
Note: initialState and customDemo are arrays of action strings, matching the
comma-separated format used in the directive. Viewers must be explicitly added using
viewer-add actions before they can be configured with images or legends.
Content Registry System#
The WIREFRAME_CONTENT_REGISTRY in docs/conf.py (lines 1166-1390) defines structured data for automatic content generation.
Registry Structure#
The registry is a nested dictionary with three types of entries:
Simple sidebars with form elements:
'settings': {
'form_elements': [
{
'type': 'select',
'label': 'Theme',
'options': ['Light', 'Dark', 'Auto']
},
{
'type': 'checkbox',
'label': 'Show tooltips'
},
{
'type': 'button',
'label': 'Apply Settings'
}
]
}
Sidebars with tabs:
'info': {
'tabs': ['File Info', 'Display Options'],
'tab_content': {
'File Info': {
'form_elements': [...]
},
'Display Options': {
'form_elements': [...]
}
}
}
Plugins sidebar:
'plugins': {
'Aperture Photometry': {
'form_elements': [
{
'type': 'select',
'label': 'Data',
'options': ['Image 1', 'Image 2']
},
{
'type': 'input',
'label': 'Radius',
'placeholder': '5.0'
}
]
},
'Model Fitting': {
'form_elements': [...]]
}
}
Currently, 16 plugins are defined in the registry:
Aperture Photometry
Line Analysis
Model Fitting
Catalog Search
Collapse
Gaussian Smooth
Moment Maps
Spectral Extraction
Data Quality
Ramp Extraction
Compass
Footprints
Orientation
Line Lists
Slit Overlay
Sonify Data
Supported Element Types#
selectDropdown menu with options array
inputText input field with optional placeholder
checkboxCheckbox with label
buttonAction button with label
Auto-generation Functions#
generate_form_html(form_elements)Converts element dictionaries to HTML strings. Automatically generates IDs for select elements based on their labels (e.g., label “Source” becomes ID
source-select).generate_content_for_sidebar(sidebar_type, plugin_name=None)Generates complete sidebar content from registry
Handles tabs, plugins, and simple sidebars
Returns dictionary with tab keys or single ‘main’ key
Form Element IDs#
Select elements are automatically assigned IDs based on their label text:
Label: “Source” → ID:
source-selectLabel: “Data Format” → ID:
data-format-selectLabel: “Viewer Type” → ID:
viewer-type-select
These IDs are useful for targeting elements with the highlight action:
:demo: loaders,loaders@3000:highlight=#source-select
JavaScript Integration#
Demo Parsing#
The JavaScript controller parses demo strings using indexOf and substring to handle:
Timing:
@1000extracts 1000ms delayActions:
:open-panelidentifies the actionValues:
=Image 2preserves spaces in parameter values
Demo Sequence Storage#
Parsed demos are stored as:
demoSequence = [
{sidebar: 'plugins', delay: 2000},
{sidebar: 'plugins', action: 'open-panel', delay: 1000},
{sidebar: 'plugins', action: 'select-data', value: 'Image 2', delay: 2000}
]
Auto-cycling Logic#
The autoCycleSidebars() function:
Iterates through demoSequence
Applies custom delays from each step
Checks
demoRepeatat completionEither loops back to start or shows restart button
Landing Page vs. Documentation Pages#
Landing Page (index.html):
Loads components via
fetch()callsProcesses Jinja2 variables with JavaScript string replacement
Uses
_staticdirectory for assetsNo Sphinx directive involved
Documentation Pages (RST files):
Uses
.. wireframe-demo::directiveSphinx processes Jinja2 variables at build time
Components embedded directly in HTML output
Supports all configuration options
Asset Copying#
The copy_wireframe_assets() function in conf.py handles asset preparation for the landing page:
Copies
wireframe-demo.cssdirectly to_staticProcesses
wireframe-base.htmlandwireframe-controller.jsReplaces
{{ jdaviz_version }}template variableReplaces
{{ descriptions.* }}variables with proper escapingHandles
|capitalizeJinja2 filter
Adding New Plugins#
To add a new plugin to the wireframe system:
Add to Registry (
docs/conf.py):'plugins': { # ... existing plugins ... 'New Plugin Name': { 'form_elements': [ {'type': 'select', 'label': 'Input Data', 'options': ['Data 1', 'Data 2']}, {'type': 'input', 'label': 'Parameter', 'placeholder': '1.0'}, {'type': 'button', 'label': 'Execute'} ] } }
Create Plugin Doc (
docs/plugins/new_plugin.rst):.. _plugins-new_plugin: ********** New Plugin ********** .. wireframe-demo:: :demo: plugins,plugins@1000:open-panel :enable-only: plugins :plugin-name: New Plugin Name :plugin-panel-opened: false :demo-repeat: false
Build and Test:
cd docs make html open _build/html/plugins/new_plugin.html
Benefits and Design Principles#
Modularity#
Each component (HTML, CSS, JS) is in its own file, making updates straightforward.
Maintainability#
Registry-based approach eliminates duplicate HTML strings across 16+ plugin pages. Single source of truth for plugin forms.
Reusability#
Same components used in landing page and documentation pages with different loading mechanisms.
Automation#
Auto-generation reduces manual work. Adding a plugin requires only registry entry, not HTML authoring.
Reduced File Size#
index.html reduced from 3382 to 967 lines by extracting components.
Accessibility Considerations#
Current implementation includes:
Keyboard-accessible buttons
Semantic HTML structure
Clear visual feedback for interactions
Future enhancements could include:
ARIA labels for screen readers
Focus management for sidebar transitions
Keyboard navigation for expansion panels
High contrast mode support
Technical Details#
Jinja2 Variable Handling#
Variables like {{ jdaviz_version }} and {{ descriptions.* }} are:
Replaced by Sphinx at build time for RST pages
Replaced by JavaScript string operations for landing page
Properly escaped for HTML and JavaScript contexts
File Paths#
Source files:
docs/_templates/wireframe-*.{html,css,js}Build output:
docs/_build/html/_static/wireframe-*.{html,css,js}Landing page loads from:
_static/or_templates/
Demo Timing Examples#
The @delay syntax controls how long each step lasts:
Default timing (2 seconds per step):
:demo: loaders,save,settings
Each sidebar shows for 2 seconds before moving to the next.
Custom timing:
:demo: loaders@1000,save@3000,settings@5000
Shows loaders for 1 second, save for 3 seconds, settings for 5 seconds.
Actions with timing:
:demo: plugins,plugins@1000:open-panel,plugins@3000:select-dropdown=Data:Image 2
Show plugins sidebar (2s default)
Wait 1 second, open panel
Wait 3 seconds, select dropdown value
Highlight with timing:
:demo: loaders,loaders:select-tab=Data,loaders@3000:highlight=#source-select
:demo-repeat: false
The highlight will:
Appear after the select-tab action completes
Last for 3 seconds (the step duration)
Remain visible since it’s the last step with no repeat
Timing tips:
First appearance of a sidebar uses default or specified timing
Actions on the same sidebar don’t re-show it (only perform the action)
Highlights clear on next step unless it’s the final step with
demo-repeat: falseUse longer durations (3000-5000ms) for complex actions users should observe
Troubleshooting#
Demo not starting#
Check
:demo:option syntaxVerify JavaScript console for errors
Ensure sidebar names match available options
For standalone actions, use
:enable-only:to disable all sidebars
Content not appearing#
Verify plugin name matches registry key exactly
Check
:plugin-name:spellingInspect browser console for JSON parsing errors
Panel not opening#
Ensure action is
open-panelnotopen_panelCheck timing: use
@delaysyntax correctlyVerify
plugin-panel-openedis set appropriately
Dropdown not selecting#
Use correct syntax:
select-dropdown=Label:ValueCheck that label and value match dropdown content (case-insensitive)
Ensure dropdown ID follows pattern (e.g.,
#source-selectfor “Source” label)Verify dropdown is populated before action executes
Highlight not appearing#
Verify CSS selector is valid and matches elements within the wireframe container
Check browser console for querySelector errors
Use browser dev tools to test selectors
Common selectors:
#id,.class,select[name="field"]
Highlight disappearing too soon#
Highlight clears on each new step
To persist: make it the last step and set
:demo-repeat: falseIncrease step duration with
@delaysyntax
Future Enhancements#
Potential improvements:
Additional demo actions (close-panel, hover-over, etc.)
Mobile-optimized wireframes with touch gestures
Keyboard navigation shortcuts
Enhanced accessibility features
Support for custom toolbar icons
Integration with actual Vue component previews
Recording and playback of user interactions
See Also#
UI/UX Style Guide - UI design guidelines
Creating a New Plugin - Creating new plugins
Jdaviz Design and Infrastructure - Build and deployment