Skip to main content

Guide | Build Multipage Apps

Compose scales easily to support complex, multipage apps.

All that's necessary is to pass a route argument to your App constructor, then use page.link() to navigate between pages.

import { Compose } from "@composehq/sdk"

const homePage = new Compose.App({
name: "Home",
route: "home-page",
handler: async ({ page, ui }) => {
page.add(() => ui.header("Home"))
page.add(() => ui.button(
"settings-btn",
{
label: "Settings",
onClick: () => page.link("settings-page")
}
))
}
})

const settingsPage = new Compose.App({
name: "Settings",
route: "settings-page",
parentAppRoute: "home-page",
handler: async ({ page, ui }) => {
page.add(() => ui.header("Settings"))
page.add(() => ui.button(
"return-btn",
{
label: "Return to home",
onClick: () => page.link("home-page")
}
))
}
})

The route argument is used to identify your app, and must be unique for every app in your project.

The parentAppRoute argument is optional, and is used to identify your app as a sub-page of another app. Setting this property will do the following:

  • Inherit permissions from the parent app. For example, if the parent app is shared with an external email, the sub-page will be too.
  • Hide the sub-page in the Compose dashboard UI, which helps declutter the UI. Don't worry - the sub-page is still accessible via the URL and programatically using page.link(). You can always override this behavior by passing a hidden argument to the constructor for the sub-page.

Passing data between pages

Data is passed between pages using the params argument, which is then read from the page.params object.

params are turned into query parameters in the URL, which allows them to persist across browser refreshes. This also means that the data will be serialized, so only basic data types should be passed (i.e. no functions or complex objects). A common pattern is to pass ids between pages, which can then be used to fetch data from a database.

import { Compose } from "@composehq/sdk"

const homePage = new Compose.App({
name: "Home",
route: "home-page",
handler: async ({ page, ui }) => {
page.add(() => ui.header("Home"))

let email = null;

page.add(() => ui.textInput("email", {
label: "Enter your email",
onEnter: (value) => email = value
}))

page.add(() => ui.button(
"settings-btn",
{
label: "Settings",
onClick: () => page.link("settings-page", {
params: {
email
}
})
}
))
}
})

const settingsPage = new Compose.App({
name: "Settings",
route: "settings-page",
handler: async ({ page, ui }) => {
const email = page.params.email;

if (email) {
const user = await fetchUser(email);
page.add(() => ui.header(`Settings for ${user.name}`))
} else {
page.add(() => ui.header("Settings"))
}

page.add(() => ui.button(
"return-btn",
{
label: "Return to home",
onClick: () => page.link("home-page")
}
))
}
})

Open pages in new tabs

You can open pages in new tabs by passing newTab: true to page.link():

page.link("settings-page", { newTab: true })