What a multi-panel ticket is and why you'd build one

A multi-panel ticket in Tickets V2 is a single ticket object that displays different content sections — or panels — based on what information you want to show or what stage a transaction is in. Instead of creating separate ticket objects for each view, you define multiple panels within one ticket and control which panel displays at any given time. This approach keeps your code organized and makes it easier to update related content without duplicating logic.

The most common use case is a ticket that changes appearance as a user moves through steps: a payment ticket might show a form panel first, then a confirmation panel after submission, then a receipt panel after processing. Each panel lives in the same ticket object, so you can pass data between them and keep state in one place.

Key Takeaways

  • Multi-panel tickets use a single ticket object with multiple named panels, each containing its own HTML, styling, and event handlers.
  • You define panels in the ticket's configuration using the panels property, which accepts an object where each key is a panel name and each value is the panel's content and behavior.
  • Switch between panels by calling the ticket's showPanel() method with the panel name, which you typically do in response to user actions or data changes.
  • Data and state persist across panel switches within the same ticket object, so you can collect information in one panel and display it in another without re-fetching.
  • Each panel can have its own event listeners and styling, but they share the ticket's overall container and lifecycle, so initialization and cleanup happen once per ticket.

Setting up the basic ticket structure with panels

Start by creating a ticket object and adding a panels property to its configuration. The panels property is an object where each key is a string name for that panel, and each value is an object containing the panel's content and behavior.

Here is a minimal example with two panels:

const myTicket = new Ticket({ container: '#ticket-container', panels: { form: { html: '<form><input type="text" id="userName"><button type="submit">Submit</button></form>', onShow: function() { console.log('Form panel is now visible'); } }, confirmation: { html: '<p>Thank you for your submission.</p>', onShow: function() { console.log('Confirmation panel is now visible'); } } }, initialPanel: 'form' });

The initialPanel property tells Tickets V2 which panel to display when the ticket first loads. If you don't set it, the first panel in the object order will display. The onShow callback runs every time that panel becomes visible, which is useful for updating content or triggering analytics.

Switching panels with showPanel() and passing data between them

To move from one panel to another, call the ticket's showPanel() method with the panel name as a string. You typically do this inside an event listener or after a condition is met.

const myTicket = new Ticket({ container: '#ticket-container', panels: { form: { html: '<form><input type="text" id="userName"><button type="submit">Submit</button></form>', onShow: function() { document.getElementById('userName').addEventListener('change', function(e) { myTicket.data.userName = e.target.value; }); document.querySelector('button').addEventListener('click', function() { myTicket.showPanel('confirmation'); }); } }, confirmation: { html: '<p>Thank you, <span id="displayName"></span>.</p>', onShow: function() { document.getElementById('displayName').textContent = myTicket.data.userName || 'Guest'; } } }, initialPanel: 'form', data: {} });

In this example, the form panel stores the user's input in myTicket.data.userName. When the button is clicked, showPanel('confirmation') switches to the confirmation panel. The confirmation panel's onShow callback reads that stored data and displays it. The data object persists across panel switches, so you never lose what the user entered.

Styling individual panels and managing visibility

Each panel can have its own CSS class or inline styles. You can add a className property to a panel's configuration, and Tickets V2 will explore that class only when that panel is visible.

const myTicket = new Ticket({ container: '#ticket-container', panels: { form: { html: '<form><input type="text"></form>', className: 'panel-form' }, loading: { html: '<p>Processing...</p>', className: 'panel-loading' }, result: { html: '<p>Done.</p>', className: 'panel-result' } }, initialPanel: 'form' });

In your CSS, you can then style each panel differently:

.panel-form { background: white; padding: 20px; } .panel-loading { background: #f0f0f0; text-align: center; } .panel-result { background: #e8f5e9; border: 1px solid green; }

When you call showPanel('loading'), Tickets V2 removes the previous panel's class and applies the new one, so your CSS handles the visual change. This keeps styling logic out of your JavaScript and makes it easier to update the look of a panel without touching the code that controls it.

Handling events and cleanup when panels change

Beyond onShow, you can define an onHide callback that runs when a panel is about to leave. This is where you clean up event listeners or save state before switching.

const myTicket = new Ticket({ container: '#ticket-container', panels: { form: { html: '<input type="text" id="field1"><button>Next</button>', onShow: function() { const input = document.getElementById('field1'); input.addEventListener('blur', function() { myTicket.data.field1 = input.value; }); }, onHide: function() { const input = document.getElementById('field1'); if (input) { input.removeEventListener('blur', null); } } }, review: { html: '<p>You entered: <span id="review1"></span></p>', onShow: function() { document.getElementById('review1').textContent = myTicket.data.field1; } } }, initialPanel: 'form' });

The onHide callback ensures that when you leave the form panel, any listeners attached to its elements are removed. This prevents memory leaks and duplicate listeners if the user navigates back to that panel later. When they do return, onShow runs again and re-attaches the listeners.

Common patterns: multi-step forms and conditional panels

A typical multi-panel ticket follows a flow: form → validation → processing → result. You can add logic to decide which panel to show next based on the data collected.

const wizard = new Ticket({ container: '#wizard', panels: { step1: { html: '<label>Email</label><input type="email" id="email"><button>Next</button>', onShow: function() { document.querySelector('button').addEventListener('click', function() { const email = document.getElementById('email').value; if (email.includes('@')) { wizard.data.email = email; wizard.showPanel('step2'); } else { alert('Invalid email'); } }); } }, step2: { html: '<label>Password</label><input type="password" id="password"><button>Submit</button>', onShow: function() { document.querySelector('button').addEventListener('click', function() { const password = document.getElementById('password').value; if (password.length >= 8) { wizard.data.password = password; wizard.showPanel('success'); } else { alert('Password must be at least 8 characters'); } }); } }, success: { html: '<p>Account created for ' + (wizard.data.email || '') + '</p>' } }, initialPanel: 'step1', data: {} });

This pattern validates input before moving forward and stores valid data in the ticket's data object. Each panel only shows its own form fields, keeping the interface straightforward. You can extend this to show different panels based on user choices — for example, if step1 asks "Do you have an account?", you could branch to either a login panel or a signup panel.

Frequently Asked Questions

Can I go back to a previous panel?

Yes. Call showPanel() with the name of any panel, regardless of which one is currently visible. The data object persists, so the user's previous entries are still there. You can add a "Back" button that calls showPanel('previousPanelName') to let users navigate backward through a form.

What happens to event listeners when I switch panels?

Event listeners attached to elements in a panel remain in memory even after the panel is hidden, unless you explicitly remove them in the onHide callback. If you don't clean them up and the user returns to that panel, onShow will run again and attach new listeners, creating duplicates. Always remove listeners in onHide to avoid this.

Can I update a panel's HTML after the ticket is created?

Tickets V2 does not provide a built-in method to change a panel's HTML after initialization. If you need dynamic content, store it in the ticket's data object and use onShow to render it into the panel's HTML each time the panel appears. Alternatively, use JavaScript to modify the DOM directly within the panel's container.

How do I pass data from one panel to another?

Use the ticket's data object. Any property you set on myTicket.data persists across all panels and panel switches. In one panel's onShow, collect user input and store it in myTicket.data.propertyName. In another panel's onShow, read from myTicket.data.propertyName and display or use it.

Can I have nested panels or panels within panels?

Tickets V2's multi-panel system is flat — each panel is a sibling of the others, not nested. If you need nested structure, build it inside a single panel's HTML using your own JavaScript or a templating library. The outer panel can manage which inner section is visible using the same showPanel pattern applied to elements within that panel.