Bubble Docs
  • Introduction
  • New? Start Here
  • What is Bubble?
  • The Glossary
  • User manual
    • Getting started
      • What is Bubble?
      • Building your first app
        • Planning features
        • Database structure
        • Design and UX
        • eCommerce and payments
          • Shopping cart
          • Checkout page
          • One-time payments
          • Subscriptions
          • Marketplace
      • Creating and managing apps
      • The Bubble editor
        • Tabs and sections
          • Design tab
            • The element tree
            • The property editor
          • Workflow tab
          • Data tab
          • Styles tab
          • Plugins tab
          • Settings tab
            • Application settings
              • Custom headers/body
              • Visual settings
              • Social media sharing
              • Translating your app
              • Email settings
              • Collaboration
            • Custom domain and DNS
          • Logs tab
        • Tools
          • Key features
          • The search tool
          • The Issue Checker
          • The element tree
          • The element property editor
          • The debugger
          • Notes
        • Previewing your app
      • Transitioning to Bubble from...
        • JavaScript
        • HTML and CSS
        • SQL
    • Design
      • Elements
        • The element hierarchy
          • The element tree
        • The page
        • Containers
          • Groups
          • Repeating groups
          • Table elements
          • Popups
          • Floating groups
          • Group focus
        • Visual elements
        • Input forms
          • Text and numbers
          • Dates and time
          • File uploads
          • Selection controls
        • Reusable Elements
      • Styling
        • Color variables
        • Font variables
        • Styles
        • Custom Fonts
      • Responsive design
        • Building responsive pages
        • Legacy articles
          • The Basics (Legacy)
          • Building Responsive Pages (Legacy)
          • Migrating Legacy Pages
          • Tips When Designing (Legacy)
      • Templates
      • The Component Library
      • Importing from Figma
    • Data
      • The database
        • Data types and fields
        • Creating, saving and deleting data
        • Finding data
        • Displaying data
        • Protecting data with privacy rules
        • The database editor
        • Export/import data
          • Exporting data
          • Importing data (CSV)
        • Working with location data
        • Using Algolia
        • Database structure by app type
          • Marketplace Apps
          • Directory & Listings Apps
          • Social Network Apps
          • SaaS Apps
          • Project Management Apps
          • CRM Apps
          • Professional Services Apps
          • On-demand Apps
          • Documentation/ CMS Apps
          • Applicant Tracking System (ATS) Apps
          • Portfolio Apps
          • Gallery Apps
          • Online Store / Ecommerce Apps
          • Blog Apps
          • Messaging App
          • Dashboards
          • Building Block Apps
          • Bubble as a backend
      • Files
      • Images
      • Static data
        • App texts (translations)
        • Option sets
      • Temporary data
        • Custom states
        • URL parameters
      • User accounts
        • Authentication plugins
          • Facebook plugin
          • Fitbit plugin
          • Google plugin
          • Instagram plugin
          • LinkedIn plugin
          • Pinterest plugin
          • Slack plugin
          • Wistia plugin
          • YouTube plugin
        • Cookies set by Bubble
      • Time, dates and time zones
    • Logic
      • The frontend and backend
      • Workflows
        • Events
          • Frontend events
            • Recurring workflows
            • Custom events
          • Backend events
            • Database trigger events
        • Actions
        • API Workflows
      • Dynamic expressions
      • Conditions
      • Navigation
        • Single-page applications (SPA)
        • Multi-page applications
        • Page slugs
    • Workload
      • Understanding workload
        • Activity types
        • The workload calculation
        • Client-side and server-side processing
      • Tracking workload
        • Measuring
          • Using App Metrics
        • Monitoring
          • Workload notifications
          • Infinite recursion protection
      • Optimizing workload
        • Optimization framework
        • Optimization checklist
          • Page load
          • Searches
          • Workflows and actions
          • Backend workflows
        • Agency showcases
          • Minimum Studio
          • Neam
          • Support Dept
    • Security
      • Bubble's security features
      • Planning app security
      • Client-side and server-side
      • Bubble account security
      • App security
      • Page security
      • Database security
      • API security
        • API Connector security
        • Data API security
        • Workflow API security
      • Flusk
        • Overview
        • Flusk plan features
        • Getting started with Flusk
        • Flusk security tools
          • The Issues Explorer
          • Issue details
          • Tools and settings
            • Pages rating
            • Database rating
        • Flusk FAQ
      • Cookies
      • Security checklist
    • Publishing your app
      • Web app
      • Native mobile app
        • Global native mobile settings
        • iOS App Store
        • Google Play Store
        • Publishing FAQ
    • AI
      • Generate apps with AI
        • About AI app generation
      • AI page designer
      • Connect to AI agents
    • Maintenance
      • Collaborators
      • Version control
        • Best practices: Version control
        • Transitioning from the legacy version control
        • Terminology: Version control
        • Version Control (legacy)
      • Commenting
      • Database maintenance
        • Copying the database
        • Restoring database backups
        • Bulk operations
          • Bulk operation methods compared
        • Wiping change history
      • Performance
        • Hard limits
        • Capacity Usage (legacy)
        • Notes on queries
      • SEO
        • Introduction to SEO
        • SEO: App
        • SEO: Page
      • Testing and debugging
        • Introduction to testing and debugging
        • The debugger
        • The server logs
        • Supported browsers
      • API workflow scheduler
    • Integrations
      • API
        • Introduction to APIs
          • What is a RESTful API?
        • The Bubble API
          • Bubble API terminology
          • Authentication
            • How to authenticate
            • No authentication
            • As a User
            • As an admin
          • The Data API
            • Data API Privacy Rules
            • Data API endpoints
            • Data API requests
          • The Workflow API
            • Workflow API privacy rules
            • Workflow API endpoints
            • API workflows
              • Creating API workflows
              • Scheduling API workflows
              • Recursive API workflows
              • API Workflow Scheduler
              • Case: Stripe notifications
        • The API Connector
          • Authentication
          • API Connector security
          • API guides
            • OpenAI
              • Authentication
              • Calls
                • ChatGPT
                  • Chat
            • Google Translate
              • How to setup Google API keys
          • Streaming API
        • API security
        • Plugins that connect to APIs
        • API Glossary
      • Plugins
        • What Plugins Can Do
        • Installing and using Plugins
        • Authentication plugins
        • Special Plugins
      • SQL Database Connector
      • Bubble App Connector
      • WorkOS
        • WorkOS SSO
        • WorkOS API
    • Infrastructure
      • Sub-apps
      • Bubble release tiers
      • Hosting and scaling
        • How Bubble hosting works
        • Scaling with Bubble
        • CDN (Cloudflare)
        • Bubble app names
        • Domain and DNS
      • Compliance
        • GDPR
        • SOC 2 Type II
        • HIPAA
        • Other frameworks and standards
    • Bubble for Enterprise
      • Hosting and infrastructure
        • Dedicated instance
          • The Dedicated editor experience
          • Technical specs
          • Main cluster dependencies
          • Customizable options
          • Migration process
            • Pre-migration
            • During migration
            • Post-migration
      • Security and compliance
        • Single sign-on (SSO)
        • GDPR
        • SOC 2 Type II
        • HIPAA
        • Other frameworks
        • Bubble's security features
      • Admin and collaboration
      • Priority support
      • Billing and Payment Guideline for Dedicated Instances
  • Core Reference
    • Using the core reference
    • Bubble's Interface
      • Design tab
      • Design tab (Legacy)
      • Workflow tab
      • Data tab
      • Styles tab
      • Styles tab (Legacy)
      • Plugins tab
      • Settings tab
      • Logs tab
      • Template tab
      • Toolbar
      • Top and context menu options
      • Deployment and version control
        • Deployment & Version Control Dropdown (legacy)
      • Notes
    • Elements
      • General properties
      • General properties (Legacy)
      • Styling properties
      • Styling Properties (Legacy)
      • Responsive Properties
      • Responsive Properties (Legacy)
      • Conditional formatting
      • States
      • Page Element
        • Page Element (Legacy)
      • Visual Elements
      • Containers
      • Container Layout Types
      • Containers (Legacy)
      • Input Forms
      • Reusable Elements
      • Element Templates (legacy)
    • Workflows
    • Events
      • General events
      • Element events
      • Custom events
      • Recurring event
      • Database trigger event
    • Actions
      • Account
      • Navigation
      • Data (things)
      • Email
      • Element
      • Custom
    • Data
      • Data Sources
      • Operators and comparisons
      • Search
      • Privacy
    • Styles
    • API
      • The Bubble API
        • The Data API
          • Authentication
          • Data API endpoints
          • Data API requests
        • The Workflow API
      • The API Connector
        • Authentication
        • Adding calls
    • Bubble-made Plugins
      • AddtoAny Share Buttons
      • Airtable
      • API Connector
      • Blockspring
      • Box
      • Braintree
      • Bubble App Connector
      • Chart.js
      • Circle Music Player
      • Draggable Elements
      • Dropzone
      • Facebook
      • Fitbit
      • Full Calendar
      • Google
      • Google Analytics
      • Google Optimize
      • Google Places
      • Ionic Elements
      • iTunes
      • Slidebar Menu
      • LinkedIn
      • Localize Translation
      • Mixpanel
      • Mouse & Keyboard Interactions
      • Multiselect Dropdown
      • Progress Bar
      • Rich Text Editor
      • Rich Text Editor (Legacy)
      • Screenshotlayer
      • SelectPDF
      • Slack
      • Segment
      • Slick Slideshow
      • SQL Database Connector
      • Star Rating
      • Stripe
      • Tinder-like Element
      • Twitter
      • YouTube
      • Zapier
    • Application Settings
      • App plan
      • General
      • Domain / email
      • Languages
      • SEO / metatags
      • API
      • Collaboration
      • Sub-apps
      • Versions
  • Account & Marketplace
    • Account and billing
      • Pricing and plans
        • Plans and billing
        • Billing cycle
        • FAQ: Pricing and Workload
      • Account Management
      • Building Apps for Others
      • Selling on the Marketplace
      • Plans & Billing (legacy)
    • Official Bubble Certification
      • Hiring certified developers
    • Building Plugins
      • The Plugin Editor
      • General Settings
      • Updating to Plugin API v4
      • Adding API Connections
      • Building Elements
      • Building Actions
      • Loading Data
      • Publishing and versioning
      • Github Integration
    • Building Templates
    • Application and data ownership
    • Marketplace policies
    • Bug reports
  • Vulnerability Disclosure Policy
  • Beta features
    • About the Beta features section
    • Native mobile apps 🔒
      • Introduction
        • What is a native mobile app?
        • Native mobile vs. web development
        • Differences in native and web elements
        • Native mobile app terminology
      • Building
        • Views and navigation
        • Native mobile actions
        • Components and gestures
        • Device resources
          • Location services
          • Camera/photo library
      • Previewing
      • Publishing
Powered by GitBook
On this page
  • The structure of SPAs
  • Setting up the page
  • Using conditions
  • Custom states
  • URL parameters
  • Using actions
  • Other ways to learn

Was this helpful?

  1. User manual
  2. Logic
  3. Navigation

Single-page applications (SPA)

This section covers navigation of single-page applications

Last updated 1 year ago

Was this helpful?

A single-page application dynamically updates and displays content within a single page, without requiring page reloads. This is done by simultaneously hiding and showing containers on the page so that the content of one replaces the other.

Single-page applications can be very quick to navigate and use, since you don't need to keep reloading the page. This also means that any data that you have loaded onto the page (such as a Do a search for) will remain in memory on that page until it's reloaded so that you don't need to load the same content repeatedly.

If you build a very complex single-page app with hundreds or even thousands of elements and workflows, this can start slowing down the page, especially on page load. So while your app can be faster to navigate after page load, the initial loading can be a bit longer, since the page contains more code.

There's no black and white answer for when to choose what, but many developers choose to go with combination of a single-page app and a multi-page app where they place all the app's most-used features on one SPA page, and move the lesser used features to other pages. This way, the daily use of the app will be snappy, and you avoid a long page load time.

Keep in mind what your app is for: users of a tool like a project management or HR app may not mind that the initial page load time is a bit longer, while your users may be less forgiving if it's an eCommerce app or blog.

The structure of SPAs

A single-page application relies on containers to update their content, and the group container in particular. While the containers can be hidden and displayed using actions, they are more commonly set up to have conditions that determine whether the group is showing or not.

The example above uses URL parameters to determine whether the group called Form 1 is visible or not (we'll return to that method later in the article).

The logical structure for most SPAs is that whenever the group is hidden, another group takes its place: Bubble switches their position instantly, and the user is unaware of the actual structure of the page; all they see is elements that instantly hide and show depending on the user's actions.

To understand how containers replace each other by collapsing their own height and width, we recommend getting to know how the responsive engine works. If you are new to this, you may be interested in checking out the article below:

Setting up the page

In a single-page application, the best way to set up your groups is to place them directly on top of each other. That way, when one group goes invisible and another takes its place, the switch seems instant to the user, and the page maintains a height relative to its visible elements.

For this to work, we need to ensure that some key settings on the elements are set up:

  1. First, navigate to the Layout tab

  2. Make sure that the Collapse when hidden box is checked. This instructs Bubble to reduce the height of the group to 0 pixels, so that the group below can take its place

  3. Leave the Animate the collapse operation unchecked. If the change is animated, the switch will not be instant.

Note also that This element is visible on page load is unchecked. This means that the group will be invisible by default, and we'll set up a condition to make it visible.

Using conditions

On pages that consist of a many groups, using conditions can be easier to keep track of. However, on pages that only have a few elements hiding and showing, actions can be quicker to set up.

Most apps will use of two options for navigation: custom states or URL parameters. Both are perfectly good solutions that come with their own pros and cons:

are variables that you can save temporarily on an element and reference in a condition to show and hide elements. They are invisible to the user, meaning that your users will only see the result, as opposed to URL parameters where they will see a change in the URL. A custom state needs to either have a default value on page load, or be set using an action.

add a parameter to the URL of the page, and you can reference this parameter in a conditional expression. The user can see that the URL changes and use the browser's back button as if they were visiting a new page. Users can also use the URL (such as sharing the URL or bookmarking it) to visit the same section of your SPA's later, whereas a custom state must be set by an action in your app.

There is no best practice for which method to choose, but we recommend getting to know each of them. If you want your users to be able to use the browser's back button (which is an expected behavior in Android apps) for example, you'll find it easier to set up using URL parameters. If you don't want your users to be able to go back in that way, or you don't want them to be able to manipulate the URL parameters, you are better off going with custom states.

Custom states

If this is your first time setting up a custom state, you may find our dedicated article useful:

Custom states need to contain a default from page load or be set by an action. They are connected to an element of your choice. In this example we'll save the custom state on the page itself: index.

Setting a default value

To set a default value, follow the steps below:

  1. First, open the element inspector of the page.

  2. Then, click the small ⓘ symbol in the top bar of the inspector

  3. If you don't have the custom state set up, click Add a new custom state, and give it a . In the type dropdown, we'll leave it as text.

  4. In the field we'll set the string form1.

Setting the value with an action

Whenever you need to change the value of a custom state you use the action:

  1. First, add the Set state of an element action to a workflow of your chocie

  2. Then, we'll chose which element the custom state is saved on. In this example, we placed it on the page, so we'll choose index

  3. If you have already created the custom state in the last step, you can choose it here. If not, you can select Create a new custom state, set its type to text and give it the name nav.

  4. In the value field, Bubble will ask for a text since this is the type we set for that custom state. You can then type in the value. In this example, we are assuming that the custom state had the default value of form1 that we set in the previous steps, and we'll set it to form2 so that this action switches visibility between the two groups.

Reading the data in the URL parameter

To set up the condition on the group element, we'll need to use a dynamic expression to check its value.

First, select the group element that you want to show with this condition. Double-click it to open up the element inspector.

When: this is the condition that instructs Bubble when to style the element. We saved the custom state on the index element (the page), so search or click on index as the data source of the expression. With index selected you will see the nav custom state available as an operator.

Properties: In the Select a property to change when true dropdown, we selected This element is visible. Note that the box is checked – this is because we set the group to be invisible by default, so we need the condition to make it visible.

You'll need to set up the condition on each group element that you want to show/hide, and provide a different value to each of them, such as form2 and form3.

URL parameters

Related articles

If this is your first time setting up URL parameters, you may find our dedicated article useful:

Let's look at how this would look if you set it up using URL parameters. URL parameters are pieces of data that you can place in the URL of the browser, consisting of a key and a value.

Setting the URL parameter

You can set a URL parameter by having it present in the URL when the page is loaded (by following a link for example) or by using the Go to page action. In this example, we'll do the latter:

  1. First, we'll add the action to a workflow. The event of the workflow can be whatever you need, such as a button or text being clicked.

  2. We are setting the Destination to be the same as the page we are already on: the index page.

  3. If you have multiple URL parameters and you want the existing parameters to remain in the URL, you can check Send current page paramerets. In the case of this example we only have one, so we'll keep this unchecked.

  4. Check the box Send more parameters to the page. This is how you set one or more URL parameters. Click the Add another parameter button to create a new row. You will be asked for a key and a value. We'll set the key to nav and the value to form1. The string you provide in key and value do not affect how the URL parameter works, but keep in mind it will be visible to your users in the browser's URL bar.

To ensure compatibility with all browsers, we recommend giving the key and value fields values that are : lowercase strings with no special characters or spaces.

Reading the data in the URL parameter

To read the URL parameter we just set, we'll set up a dynamic expression in the Conditional tab of the first group. Let's return to the screenshot from earlier and go over how it works:

When: this is the condition that instructs Bubble when to style the element. We are using the Get data from URL data source, and the name (key) of the URL parameter is nav. You can use whichever name you want – just keep in mind that your users will see it in the URL bar.

Properties: In the Select a property to change when true dropdown, we selected This element is visible. Note that the box is checked – this is because we set the group to be invisible by default, so we need the condition to make it visible.

To summarize then logic, let's look at the condition as a humanly readable sentence:

When the URL parameter called nav contains the text form1, make this element visible.

To make this logic work on your other groups, simply set up the same condition on them, but change the value of the URL parameter, such as nav=form2 and nav=form3.

Using actions

You can also show and hide elements using actions. The result to the user will be the same, so we are simply using a different method to reach the same goal.

On pages that consist of a few groups, using actions can be quicker to set up. However, on pages that have a lot of elements hiding and showing, conditions can be easier to keep track of.

Using the show/hide an element actions

To instruct Bubble to show or hide an element we have two actions to choose from and . Note that these are separate actions and not the same one:

  1. First, add the Show an element action to a workflow of your choice

  2. Then, select the element that you want to show. In this case we want to show the group called Form 1.

Using the toggle an element action

If you want the same action to toggle the visibility of the element, you can use the action. This will do exactly the same as the show/hide an element actions, except you only need one action:

  1. First, add the Toggle an element action to a workflow of your choice

  2. Then, select the element to toggle. In this case we want to toggle the group called Form 1.

Other ways to learn

Video lessons

Article:

Article: Reference:

Article: Reference:

Responsive design
How to use the toggle action to show/hide elements
Custom states
URL parameters
The set state of an element action
The Get data from page URL data source
In this example, we have two groups placed on top of each other. When one his hidden, it collapses its height and the other group takes its place. To the user, the switch is instant.