Best approach for navigation in a web app?

Hi all,

I’m wondering if there is an “best” approach for navigating through a web app?

At first I just created multiple web pages and had to copy/paste fixed background elements which quickly became tiresome as number of pages increased and having to maintain subsequent changes consistently.

Then I experimented with webContainers which allows me to maintain one single master page and just swap out content. Which then led to having to create a class to navigate back/forward/to specific container content, to simulate page/screen navigation in the web app.

I guess this works but am wonder if I may have over-engineered it, and if there is some more widely accepted way of doing this?

Many thanks

Stam

I feel like you’ve over-engineered this. To be honest, your container solution is darn near identical to how the pages are loaded in the first place for web pages, so…

I would suggest a hybrid approach. Make a container with the common stuff and then when you first start a webpage, drag one of those onto the page and continue adding other controls.

If you still feel that you need back/forward button control, look at Session.SaveState and the HashTagChanged events. Those let you store state and get that state back when the user clicks back or forward.

Thanks Greg, I’ll look into that.

Does this only work with the browser’s back button as suggested by the documentation?

Or can this be triggered by a webbutton.pressed event? (my ‘Cancel’ buttons will frequently just navigate back and it would be good not to hardcode each ‘back’ destinations for each of these).

Interestingly, I fed my project into Claude AI, and asked it if my web app specifically would benefit form my current approach or switching to Greg’s suggestion of a hybrid approach.

Claude AI’s response was that I should stick with current implementation for my web app (a “shell” page for static content, webcontainer subclass for dynamic content), because with my current approach, the active content webcontainers are just hidden, not closed/removed from memory (a side effect of having to navigate back and forth).

As a result, saving state is much simpler as it never goes away or has to be reloaded. State in my case refers to multiple complex forms, with session-peristent save for later review (rather than submit) and review of multiple looping videos where flashing is to be avoided.
I really did not expect this answer…

I generalised the question: when should I use one or the other and the answer is it depends on use case (of course). My approach is good for some stuff, not others. Detailed response from Claude AI below (may be of interest to some):

Read Claude AI's view on merits and trade-offs

Merits of Using Template Shell + WebContainers for Dynamic Content

This architecture pattern has significant advantages for certain types of web applications. Let me break down the key merits:


1. State Preservation

The Merit

WebContainers remain in memory when hidden, preserving their entire state automatically.

When This Matters

  • Complex forms with many fields (users navigate away and come back)

  • Multi-step processes where users might jump between steps

  • Draft functionality where work-in-progress needs to persist in the session

  • Undo/redo operations that rely on maintaining history

Example Scenarios

  • Survey applications where users review previous answers

  • E-commerce checkout with multiple steps

  • Document editors with multiple panels/views

  • Configuration wizards where users compare options across screens


2. Seamless Transitions

The Merit

No page reloads = no flashing, no loss of scroll position, no interruption of media or animations.

When This Matters

  • Media playback (audio/video/animations) that should continue across views

  • Real-time data (live charts, streaming data) that shouldn’t reset

  • Smooth UX where page flashes would feel jarring

  • Complex visualizations that take time to render

Example Scenarios

  • Media players with navigation sidebar

  • Real-time dashboards with multiple view modes

  • CAD/design applications with tool panels

  • Video conferencing with multiple screens


3. Controlled Navigation

The Merit

Complete programmatic control over navigation logic, history, and user flow.

When This Matters

  • Conditional navigation based on business rules

  • Preventing navigation to certain states (e.g., can’t go back after submission)

  • Custom history management (not just linear back/forward)

  • Workflow enforcement where users must complete steps in order

Example Scenarios

  • Testing/assessment platforms (can’t review answers after submission)

  • Banking transactions (can’t go back once confirmed)

  • Onboarding flows with branching logic

  • Medical diagnosis workflows with step dependencies


4. Shared Context & Components

The Merit

The shell provides persistent context (headers, footers, sidebars) that doesn’t reload.

When This Matters

  • Real-time notifications in a header that persist across views

  • Shopping cart indicators that update without page refresh

  • User presence indicators in collaboration apps

  • Global search that remains accessible and stateful

  • Persistent chat/help widgets

Example Scenarios

  • E-commerce sites with persistent cart display

  • Collaboration tools with presence indicators

  • SaaS apps with notification centers

  • Help desk systems with chat widgets


5. Performance Benefits

The Merit

Only the dynamic content area changes; shell elements stay in memory.

When This Matters

  • Complex headers/footers with heavy JavaScript/styling

  • Repeated navigation between views in a session

  • Resource-intensive components in the shell (maps, charts)

  • Reduced server requests (no need to re-fetch shell HTML)

Example Scenarios

  • Apps with complex navigation menus with mega-dropdowns

  • Dashboards with persistent data visualizations in sidebars

  • Maps applications where the map frame stays loaded

  • Admin panels with rich navigation trees


6. Simplified State Management

The Merit

Less need for explicit state serialization/deserialization across navigation.

When This Matters

  • Complex object graphs that are expensive to serialize

  • Temporary UI state (expanded accordions, scroll positions, selections)

  • Computed values that don’t need to be recalculated

  • Event handlers and timers that can continue running

Example Scenarios

  • Data grids with complex sorting/filtering/grouping state

  • File managers with selection state across folders

  • IDEs with open tabs and editor state

  • Project management tools with expanded/collapsed sections


7. Easier Testing & Debugging

The Merit

Navigation logic is centralized and programmatic, making it easier to test and debug.

When This Matters

  • Unit testing navigation flows without browser automation

  • Debugging navigation issues with clear entry/exit points

  • Logging navigation history for analytics or support

  • A/B testing different navigation patterns


When NOT to Use This Pattern

This architecture has trade-offs:

:cross_mark: SEO Requirements

  • Search engines struggle with single-page apps

  • Each “page” doesn’t have a unique URL (without extra work)

  • Better alternative: Traditional multi-page with server-side rendering

:cross_mark: Simple, Document-Based Sites

  • Blogs, marketing sites, documentation

  • No complex state to preserve

  • Better alternative: Standard page navigation or static site generators

:cross_mark: Deep Linking Requirements

  • Users need to bookmark specific states

  • Sharing URLs to specific views

  • Mitigation: Requires hash-based routing or History API implementation

:cross_mark: Memory Constraints

  • Many containers in history consume memory

  • Mobile devices with limited resources

  • Mitigation: Implement container disposal strategies

:cross_mark: Browser Back/Forward Expectations

  • Users expect standard browser navigation

  • Mitigation: Implement hash-based routing (added complexity)


Ideal Use Cases Summary

This pattern excels for:

  1. Single-page applications (SPAs) with complex workflows

  2. Dashboard-style interfaces with multiple views

  3. Media-centric applications (video, audio, streaming)

  4. Data entry applications with extensive forms

  5. Collaboration tools with real-time updates

  6. Wizard/workflow applications with strict navigation rules

  7. Testing/assessment platforms with non-rewindable flows

  8. Tools and utilities (calculators, designers, editors)


Modern Web Context

This pattern in XOJO is conceptually similar to:

  • React Router with component-based routing

  • Vue Router with view components

  • Angular routing with lazy-loaded modules

  • Turbo/Hotwire partial page replacement

The shell + container pattern is essentially a component-based SPA architecture implemented in XOJO Web, and it brings the same benefits (and challenges) as modern JavaScript SPA frameworks.

Bottom line: Use this pattern when you need rich, stateful, application-like behavior in the browser. Use traditional page-based navigation when you need SEO, deep linking, or are building document-centric sites.