### Run your app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/fast-api.mdx Start your FastAPI server using `fastapi dev`. ```bash fastapi dev main.py ``` -------------------------------- ### Starter code for app.py (Manual Install) Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Provides starter code for the app.py file, including basic Compose SDK setup. ```python import compose_sdk as c # For demo purposes. In a real app, you'd use your actual database. db_users = [ { "name": "John Doe", "email": "john@doe.com" }, { "name": "Jane Smith", "email": "jane@smith.com" }, ] def view_users_handler(page: c.Page, ui: c.UI): page.add(lambda: ui.header("View Users", size="lg")) users = [*db_users] # fake database call page.add(lambda: ui.table("users-table", users)) def create_user_handler(page: c.Page, ui: c.UI): def on_submit(form): db_users.append({ "name": form["name"], "email": form["email"] }) page.toast("User created successfully", appearance="success") page.link("view-users") page.add(lambda: ui.header("Create User", size="lg")) page.add(lambda: ui.form( "create-user-form", [ ui.text_input("name"), ui.email_input("email") ], on_submit=on_submit )) nav = c.Navigation(["view-users", "create-user"]) client = c.Client( api_key="API_KEY_HERE", # replace with your own API key apps=[ c.App(route="view-users", navigation=nav, handler=view_users_handler), c.App(route="create-user", navigation=nav, handler=create_user_handler) ] ) client.connect() ``` -------------------------------- ### Start the Compose Client Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/python.mdx In the main entry point of your project, e.g. `main.py`, add the following: ```python from .compose import compose_client # ... other code ... # Run the client in a background thread. Use .connect() to run the client # as a blocking process in the main thread. compose_client.connect_async() ``` -------------------------------- ### Python App Example Source: https://github.com/compose-dev/docs/blob/main/docs/introduction.mdx This Python code demonstrates how to define a Compose App that fetches users from a database and displays them in a table. ```python import compose_sdk as c from database import database def view_users_handler(page: c.Page, ui: c.UI): users = database.select_users() # query your database page.add(lambda: ui.table("users-table", users)) # display results in a table view_users_app = c.App(route="view-users", handler=view_users_handler) ``` -------------------------------- ### Run your app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/flask.mdx Start your Flask server. Compose will automatically connect in the background. ```bash flask --app main run ``` -------------------------------- ### Run your app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/django.mdx Start your Django server. Compose will automatically connect in the background. ```bash python manage.py runserver ``` -------------------------------- ### Separate Deployment Example (Node.js) Source: https://github.com/compose-dev/docs/blob/main/docs/guides/deployment.mdx Example of how to configure a Node.js application for a separate Compose deployment. ```javascript import { Compose } from "@composehq/sdk"; import express from "express"; const server = express(); server.get("*", (req, res) => { res.send("Hello World"); }); const client = new Compose.Client({ apiKey: process.env.COMPOSE_API_KEY, apps: [...], }); // highlight-start const deploymentType: "server" | "compose" = process.env.DEPLOYMENT_TYPE || "server"; if (deploymentType === "compose") { client.connect(); } else { server.listen(process.env.PORT || "3000"); } // highlight-end ``` -------------------------------- ### Start the Compose Client Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/flask.mdx In the main entry point of your project, e.g. `main.py`, add the following: ```python from flask import Flask, jsonify from .compose import compose_client import os # Avoid running the client in the auto-reload process if os.environ.get("WERKZEUG_RUN_MAIN") == "true": compose_client.connect_async() app = Flask(__name__) ``` -------------------------------- ### Run the app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Starts the Node.js application in development mode. ```bash npm run dev ``` -------------------------------- ### Separate Deployment Example (Python) Source: https://github.com/compose-dev/docs/blob/main/docs/guides/deployment.mdx Example of how to configure a Python Flask application for a separate Compose deployment. ```python # Example Flask app import compose_sdk as c from flask import Flask import os client = c.Client( api_key=os.environ.get("COMPOSE_API_KEY"), apps=[...], ) # highlight-start deployment_type: "server" | "compose" = os.environ.get("DEPLOYMENT_TYPE") if deployment_type == "compose": client.connect() # highlight-end server = Flask(__name__) @server.route("/") def say_hello(): return "

Hello, World!

" def main(page: c.Page, ui: c.UI): page.add(lambda: ui.text("Hello world!")) ``` -------------------------------- ### TypeScript / JavaScript App Example Source: https://github.com/compose-dev/docs/blob/main/docs/introduction.mdx This TypeScript/JavaScript code demonstrates how to define a Compose App that fetches users from a database and displays them in a table. ```typescript import { Compose } from "@composehq/sdk"; import { database } from "../database"; const viewUsersApp = new Compose.App({ route: "view-users", handler: async ({ page, ui }) => { const users = await database.selectUsers() // query your database page.add(() => ui.table("users-table", users)); // display results in a table } }) ``` -------------------------------- ### File upload example (TypeScript/JavaScript) Source: https://github.com/compose-dev/docs/blob/main/docs/guides/working-with-files.mdx An example demonstrating how to use the `ui.fileDrop` component to upload PDF files and save them to the server. ```javascript import { Compose, Page, UI } from "@composehq/sdk" import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); function handler({ page, ui }: { page: Page, ui: UI }) { let files: { buffer: Buffer, name: string, type: string }[] = []; function onFiles(newFiles: { buffer: Buffer, name: string, type: string }[]) { newFiles.forEach(file => { const filePath = path.join(__dirname, file.name); fs.writeFileSync(filePath, file.buffer); }); files = [...files, ...newFiles]; page.update(); } page.add(() => ui.fileDrop("pdf-file-drop", { label: "Drop files here", acceptedFileTypes: ["application/pdf"], onChange: onFiles })) page.add(() => ui.cond(files.length > 0, { true: ui.text(`Received ${files.length} files.`), false: ui.text("No files received yet.") })) } const app = new Compose.App({ route: "file-upload", handler }) ``` -------------------------------- ### Example Flask app Source: https://github.com/compose-dev/docs/blob/main/docs/guides/deployment.mdx Deploying Compose as a dependency inside an existing server environment using Python. ```python # Example Flask app import compose_sdk as c from flask import Flask import os client = c.Client( api_key=os.environ.get("COMPOSE_API_KEY"), apps=[...], ) # Compose will run safely in a separate thread, while your server handles regular traffic. if os.environ.get("WERKZEUG_RUN_MAIN") == "true": client.connect_async() server = Flask(__name__) @server.route("/") def say_hello(): return "

Hello, World!

" def main(page: c.Page, ui: c.UI): page.add(lambda: ui.text("Hello world!")) ``` -------------------------------- ### File upload example (Python) Source: https://github.com/compose-dev/docs/blob/main/docs/guides/working-with-files.mdx An example demonstrating how to use the `ui.file_drop` component to upload PDF files and handle them in a Python application. ```python import compose_sdk as c def handler(page: c.Page, ui: c.UI): files: list[c.File] = [] def on_files(new_files: list[c.File]): nonlocal files files.extend(new_files) page.update() page.add(lambda: ui.file_drop( "pdf-file-drop", label="Drop files here", accepted_file_types=["application/pdf"], on_change=on_files )) page.add(lambda: ui.cond( len(files) > 0, true=ui.text(f"Received {len(files)} files."), false=ui.text("No files received yet.") )) const app = new c.App(route="file-upload", handler=handler) ``` -------------------------------- ### Example Express app Source: https://github.com/compose-dev/docs/blob/main/docs/guides/deployment.mdx Deploying Compose as a dependency inside an existing server environment using TypeScript/JavaScript. ```javascript // Example Express app import { Compose } from "@composehq/sdk"; import express from "express"; const server = express(); server.get("*", (req, res) => { res.send("Hello World"); }); const helloWorldApp = new Compose.App({ route: "hello-world", handler: async ({ page, ui }) => { page.add(() => ui.text("Hello Worldenhavn")); } }) const client = new Compose.Client({ apiKey: process.env.COMPOSE_API_KEY, apps: [helloWorldApp], }); // Compose will run safely in the background, while your server handles regular traffic. client.connect(); server.listen(process.env.PORT || "3000"); ``` -------------------------------- ### Install the SDK Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/fast-api.mdx Install the Compose SDK using pip. ```bash pip install compose-sdk ``` -------------------------------- ### Start the Compose Client Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/django.mdx In the `apps.py` file of the Compose app, add the following code to initialize the Compose client and connect it asynchronously. This code includes dynamic imports to prevent AppRegistryNotReady errors and ensures the client does not start during the auto-reload process. ```python from django.apps import AppConfig import os import compose_sdk as c class ComposeConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'compose' def ready(self): # Don't start in the auto-reload process if os.environ.get("RUN_MAIN") != "true": return # Do dynamic imports to avoid AppRegistryNotReady errors from .starter_apps import view_users_app, create_user_app client = c.Client( api_key="API_KEY_HERE", apps=[view_users_app, create_user_app] ) client.connect_async() ``` -------------------------------- ### Set initial input values Source: https://github.com/compose-dev/docs/blob/main/docs/guides/forms.mdx Example of setting initial values for form inputs using the `initialValue` parameter. ```javascript function editUser(user) { page.modal(({ resolve }) => ui.form( "edit-user", [ // highlight-start ui.textInput("name", { initialValue: user.name }), ui.emailInput("email", { initialValue: user.email }), // highlight-end ], { onSubmit: (form) => { editUser(user.id, form.name, form.email) resolve() // close modal } } ) ) } ``` ```python def edit_user(user_id, name, email, resolve): update_user(user_id, name, email) resolve() # close modal def edit_user_modal(user): page.modal(lambda resolve: ui.form( "edit-user", [ # highlight-start ui.text_input("name", initial_value=user["name"]), ui.email_input("email", initial_value=user["email"]), # highlight-end ], "on_submit": lambda form: edit_user(user["id"], form["name"], form["email"], resolve) ) ) ``` -------------------------------- ### Python Example Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/how-it-works.mdx Example of a reactive app in Python demonstrating how callbacks are managed for UI updates. ```python def handler(page: c.Page, ui: c.UI): count = 0 def on_click(): nonlocal count count += 1 page.update() page.add(lambda: ui.text(f"Count: {count}")) page.add(lambda: ui.button("increment", on_click=on_click)) ``` -------------------------------- ### Run your app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/python.mdx Run your project's dev server. Compose will automatically connect in the background. ```bash python main.py ``` -------------------------------- ### Activate the virtual environment (Manual Install) Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Activates the virtual environment on different operating systems for manual installation. ```bash # macOS/Linux source .venv/bin/activate # Windows command prompt .venv\Scripts\Activate.bat # Windows PowerShell .venv\Scripts\Activate.ps1 ``` -------------------------------- ### Install py-mon (Manual Install) Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Optionally installs py-mon for auto-reloading code changes. ```bash pip install py-mon ``` -------------------------------- ### TypeScript / JavaScript File Download Source: https://github.com/compose-dev/docs/blob/main/docs/guides/working-with-files.mdx This example demonstrates how to download a file using a Buffer and filename string in TypeScript/JavaScript. ```javascript import { Compose, Page, UI } from "@composehq/sdk"; import fs from 'fs'; function handler({ page, ui }: { page: Page, ui: UI }) { function onDownload() { const fileName = "image.png"; // Read the file into a Buffer const buffer = fs.readFileSync(pathToFile); // Download to user's computer page.download(buffer, fileName) } page.add(() => ui.button("download-btn", { label: "Download PDF", onClick: onDownload })) } const app = new Compose.App({ route: "file-download", handler }) ``` -------------------------------- ### Install the Compose SDK Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Installs the Compose SDK package using npm. Requires Node.js 16 or higher. ```bash npm install @composehq/sdk ``` -------------------------------- ### Setup Comparison Source: https://github.com/compose-dev/docs/blob/main/docs/guides/migrate-from-interval.mdx Compares the setup process for Compose and Interval, highlighting programmatic route definition in Compose versus file-based routing in Interval. ```typescript import { Compose } from "@composehq/sdk"; const app = new Compose.App({ route: "my-app", // Define the route programmatically handler: async ({ page, ui }) => { page.add(() => ui.text(`Hello World`)); } }) const client = new Compose.Client({ apiKey: "YOUR_API_KEY", apps: [app] // Pass the list of apps to serve to the client }) client.connect() ``` ```typescript // src/routes/my-app.ts import { Action, io } from "@interval/sdk"; export default new Action(async () => { return "Hello World" }) // src/tools.ts import path from "path"; import { Interval } from "@interval/sdk"; const interval = new Interval({ apiKey: "YOUR_API_KEY", routesDirectory: path.resolve(__dirname, "routes"), }); interval.listen() ``` -------------------------------- ### Create a project directory Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Creates a new directory for the project. ```bash mkdir compose && cd compose ``` -------------------------------- ### Python SDK Example Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/concepts.mdx Example of how to import Compose, define a handler, create an app, and initialize the client in Python. ```python # 1: Import Compose from the SDK import compose_sdk as c # 2: Define a handler function for your app def handler(page: c.Page, ui: c.UI): users = database.fetch_users() page.add(lambda: ui.table("users", users)) # 3: Create an app by passing a unique route key and a handler function users_app = c.App(route="users-dashboard", handler=handler) # 4: Create the client by passing in the API key and the list of apps to serve client = c.Client( api_key="", apps=[users_app], ) # 5: Initialize the connection to the Compose servers client.connect() ``` ```bash python your_script.py # or, use pymon to automatically restart your server as you save changes pymon your_script.py ``` -------------------------------- ### Python File Download Source: https://github.com/compose-dev/docs/blob/main/docs/guides/working-with-files.mdx This example shows how to download a file using bytes or a bytes-like object and a filename string in Python. ```python import compose_sdk as c import io import os def handler(page: c.Page, ui: c.UI): def on_download(): # Read the file into a bytes object with open(path_to_file, "rb") as file: file_name = "image.png" # Download to user's computer page.download(file.read(), file_name) page.add(lambda: ui.button( "download-btn", label="Download PDF", on_click=on_download )) const app = new c.App("file-upload", handler) ``` -------------------------------- ### TypeScript / JavaScript Example Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/how-it-works.mdx Example of a reactive app in TypeScript/JavaScript demonstrating how callbacks are managed for UI updates. ```javascript function handler({ page, ui }) { let count = 0; page.add(() => ui.text(`Count: ${count}`)); page.add(() => ui.button("increment", { onClick: () => { count += 1; page.update(); } })) } ``` -------------------------------- ### Install dependencies Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Installs project dependencies from the requirements.txt file. Requires Python 3.9 or higher. ```bash pip install -r requirements.txt ``` -------------------------------- ### Create a virtual environment Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Creates a Python virtual environment for the project. ```bash python -m venv .venv ``` -------------------------------- ### Install dependencies Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Installs project dependencies using npm. Requires Node.js 16 or higher. ```bash npm install ``` -------------------------------- ### TypeScript / JavaScript SDK Example Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/concepts.mdx Example of how to import Compose, define a handler, create an app, and initialize the client in TypeScript/JavaScript. ```ts // 1: Import Compose from the SDK import { Compose, Page, UI } from "@composehq/sdk" // 2: Define a handler function for your app const handler = ({ page, ui }: { page: Page, ui: UI }) => { const users = database.fetchUsers() // do your own business logic page.add(() => ui.table("users", users)) // call SDK method to render UI } // 3: Create an app by passing a unique route key and a handler function const usersApp = new Compose.App({ route: "users-dashboard", handler }); // 4: Create the client by passing in the API key and the list of apps to serve const client = new Compose.Client({ apiKey: "", apps: [usersApp] }); // 5: Initialize the connection to the Compose servers client.connect(); ``` ```bash node --watch your_script.js ``` -------------------------------- ### Python DateTime Input Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/datetime-input.mdx Example of how to render a datetime input box using Python. ```python ui.datetime_input( "date-input-key", label="When will the world end?", on_enter=lambda value: print(value) ) ``` -------------------------------- ### Install TypeScript and tsx Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Installs TypeScript and tsx as development dependencies for TypeScript projects. ```bash npm install --save-dev typescript tsx ``` -------------------------------- ### Interval Form Example Source: https://github.com/compose-dev/docs/blob/main/docs/guides/migrate-from-interval.mdx Example of creating a form with text and email inputs in Interval. ```typescript import { Action, io } from "@interval/sdk"; export default new Action(async () => { const [name, email] = await io.group([ io.input.text("name"), io.input.email("email") ]) await createUser(name, email) }) ``` -------------------------------- ### CRUD App Example Source: https://github.com/compose-dev/docs/blob/main/docs/examples/crud-app.mdx This code snippet demonstrates a full CRUD (Create, Read, Update, Delete) application. It includes functions for creating, editing, and deleting users, and displays them in a table with actions. ```python from typing import Dict from nicegui import ui # Dummy data for users users: Dict[str, Dict] = { "user1": {"name": "Alice", "email": "alice@example.com", "confirmedEmail": "alice@example.com"}, "user2": {"name": "Bob", "email": "bob@example.com", "confirmedEmail": "bob@example.com"}, } def on_submit_form(data: Dict, resolve): """Callback function for form submission.""" if "id" in data: # Update existing user users[data["id"]] = data else: # Create new user users[f"user{len(users) + 1}"] = data resolve() def create_user(): """Opens a dialog to create a new user.""" edit_user(id=None) def edit_user(id: str | None = None): """Opens a dialog to edit an existing user or create a new one.""" user = users.get(id) if id else {} ui.dialog() with ui.card(): with ui.form(save_button=True) as form: ui.input(label="Name", value=user.get("name")).bind_value(user, "name") ui.input(label="Email", value=user.get("email")).bind_value(user, "email") ui.input(label="Confirmed Email", value=user.get("confirmedEmail")).bind_value(user, "confirmedEmail") if id: ui.hidden_input(name="id", value=id) async def resolve(): await form.validate() on_submit_form(user, ui.close_dialog) ui.button("Save", on_click=resolve) def delete_user(id: str): """Deletes a user.""" del users[id] ui.update_table("users-table") def handler(page: ui.Page): """Main handler for the CRUD app.""" page.title = "CRUD App" # Dialog for creating/editing users with ui.dialog() as dialog, ui.card(): with ui.form(save_button=True) as form: ui.input(label="Name").bind_value(user, "name") ui.input(label="Email").bind_value(user, "email") ui.input(label="Confirmed Email").bind_value(user, "confirmedEmail") if id: ui.hidden_input(name="id", value=id) async def resolve(): await form.validate() on_submit_form(user, dialog.close) ui.button("Save", on_click=resolve) # Show a table of users, with actions to create, edit, and delete users. page.add( lambda: ui.stack( [ ui.distributed_row([ ui.header("Users", size="sm"), ui.button("create-user", on_click=create_user), ]), ui.table( "users-table", users, columns=["name", "email", "confirmedEmail"], actions=[ { "label": "Edit", "on_click": edit_user, "surface": True, }, { "label": "Delete", "on_click": delete_user, "surface": True, }, ], ), ] ) ) crud_app = ui.App( route="crud-app", handler=handler, ) ``` -------------------------------- ### Compose Form Example Source: https://github.com/compose-dev/docs/blob/main/docs/guides/migrate-from-interval.mdx Example of creating a form with text and email inputs and an onSubmit callback in Compose. ```typescript import { Compose, Page, UI } from "@composehq/sdk"; function handler({ page, ui }: { page: Page, ui: UI }) { page.add(() => ui.form( "new-user", [ ui.textInput("name"), ui.emailInput("email") ], { onSubmit: async (formData) => { await createUser(formData.name, formData.email) page.toast("User created") }, } )) } const app = new Compose.App({ route: "my-app", handler }) ``` -------------------------------- ### Python Manual Pagination Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx Example of implementing manual pagination using a getter function for the `data` parameter in Python. ```python import compose_sdk as c def on_page_change(args: c.TablePageChangeArgs) -> c.TablePageChangeResponse: # Unpack arguments offset = args["offset"] page_size = args["page_size"] refresh_total_records = args["refresh_total_records"] prev_total_records = args["prev_total_records"] search_query = args["search_query"] # optional to handle search sort_by = args["sort_by"] # optional to handle sorting filter_by = args["filter_by"] # optional to handle filtering # Only recalculate total records when needed total_records = ( postgres.count_users(search_query, filter_by, sort_by) if refresh_total_records or prev_total_records is None else prev_total_records ) page_of_users = postgres.get_users(offset, page_size, search_query, sort_by, filter_by) return {"data": page_of_users, "total_records": total_records} page.add(lambda: ui.table("users-table", on_page_change)) ``` -------------------------------- ### Python Source: https://github.com/compose-dev/docs/blob/main/docs/guides/styling-your-app.mdx Example of styling a text input component in Python. ```python import compose_sdk as c def handler(page: c.Page, ui: c.UI): page.add(lambda: ui.text_input("email", style={"width": "20rem", "fontSize": "24px"})) ``` -------------------------------- ### Activate the virtual environment Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Activates the virtual environment on different operating systems. ```bash # Mac/Linux source .venv/bin/activate # Windows (Command Prompt) .venv\Scripts\Activate.bat # Windows (PowerShell) .venv\Scripts\Activate.ps1 ``` -------------------------------- ### Node.js DateTime Input Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/datetime-input.mdx Example of how to render a datetime input box using TypeScript/JavaScript. ```javascript ui.dateTimeInput("date-input-key", { label: "When will the world end?", onEnter: (value) => console.log(value) }) ``` -------------------------------- ### Node.js/TypeScript CRUD Example Source: https://github.com/compose-dev/docs/blob/main/docs/examples/crud-app.mdx This code snippet shows a full CRUD application example in TypeScript, including functions for creating, reading, updating, and deleting users. It utilizes various Compose SDK components like `Page`, `UI`, `Tabs`, `TabItem`, `header`, `text`, `stack`, `distributedRow`, `button`, `confirm`, `toast`, `modal`, and `form`. ```typescript import { Compose, Page, UI } from "@composehq/sdk"; interface User { id: number; name: string; email: string; confirmedEmail: boolean; } // This is a fake list of users. In a real app, you'd likely be using a database. const dbUsers: User[] = [ { id: 1, name: "John Doe", email: "john.doe@example.com", confirmedEmail: true }, { id: 2, name: "Jane Smith", email: "jane.smith@example.com", confirmedEmail: false }, { id: 3, name: "Bob Johnson", email: "bob.johnson@example.com", confirmedEmail: true }, { id: 4, name: "Alice Brown", email: "alice.brown@example.com", confirmedEmail: true }, { id: 5, name: "Charlie Wilson", email: "charlie.wilson@example.com", confirmedEmail: false }, { id: 6, name: "Eva Green", email: "eva.green@example.com", confirmedEmail: true }, { id: 7, name: "David Lee", email: "david.lee@example.com", confirmedEmail: false }, { id: 8, name: "Fiona White", email: "fiona.white@example.com", confirmedEmail: true }, { id: 9, name: "George Black", email: "george.black@example.com", confirmedEmail: true }, { id: 10, name: "Helen Gray", email: "helen.gray@example.com", confirmedEmail: false }, ]; function handler({ page, ui }: { page: Page; ui: UI; }) { let users: User[] = [...dbUsers]; // fake db query to fetch users page.add(() => ui.stack([ ui.header("Users Dashboard"), ui.text("This is a demo!"), ]) ); async function deleteUser(user: User) { const confirmed = await page.confirm({ title: "Delete User", message: "Are you sure you want to delete this user?", typeToConfirmText: user.name, }); if (confirmed) { users = users.filter((u) => u.id !== user.id); page.update(); page.toast("User deleted successfully!", { appearance: "success" }); } } async function editUser(user: User, idx: number) { page.modal( ({ resolve }) => ui.form( "edit-user-form", [ ui.textInput("name", { initialValue: user.name }), ui.emailInput("email", { initialValue: user.email }), ui.checkbox("confirmedEmail", { initialValue: user.confirmedEmail }), ], { onSubmit: (formData) => { users[idx] = { ...users[idx], ...formData }; page.update(); page.toast("User updated successfully!", { appearance: "success" }); // Close the modal resolve(); }, } ), { title: "Edit User" } ); } async function createUser() { page.modal( ({ resolve }) => ui.form( "create-user-form", [ ui.textInput("name"), ui.emailInput("email"), ui.checkbox("confirmedEmail"), ], { onSubmit: (formData) => { const newUser = { id: users.length + 1, name: formData.name, email: formData.email, confirmedEmail: formData.confirmedEmail, }; users.push(newUser); page.update(); page.toast("User created successfully!", { appearance: "success" }); resolve(); // Close the modal }, } ), { title: "Create User" } ); } // Show a table of users, with actions to create, edit, and delete users. page.add(() => ui.stack([ ui.distributedRow([ ui.header("Users", { size: "sm" }), ui.button("create-user", { onClick: createUser, }), ]), ``` -------------------------------- ### Formatting Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx Example of how to format table columns with different options. ```javascript const users = [ { name: "John", createdAt: new Date("2021-01-01"), isActive: true, tier: "Enterprise" }, { name: "Jane", createdAt: new Date("2021-01-02"), isActive: false, tier: "Basic" }, ] ui.table("table-key", users, { columns: [ "name", { key: "createdAt", format: "date", width: "150px" }, { key: "isActive", label: "Status", format: "boolean" }, { key: "tier", format: "tag", tagColors: { "blue": ["Enterprise", "Pro"], "green": "Basic" } } ] }) ``` ```python users = [ {"name": "John", "created_at": datetime(2021, 1, 1), "is_active": True, "tier": "Enterprise"}, {"name": "Jane", "created_at": datetime(2021, 1, 2), "is_active": False, "tier": "Basic"}, ] ui.table( "table-key", users, columns=[ "name", {"key": "created_at", "format": "date", "width": "150px"}, {"key": "is_active", "label": "Status", "format": "boolean"}, {"key": "tier", "format": "tag", "tag_colors": { "blue": ["Enterprise", "Pro"], "green": "Basic" }} ] ) ``` -------------------------------- ### DataFrame Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/dataframe.mdx Render a pandas DataFrame. ```python import pandas as pd df = pd.DataFrame({ 'name': ['John', 'Jane', 'Bob'], 'age': [30, 25, 35], 'city': ['New York', 'London', 'San Francisco'] }) ui.dataframe( "dataframe-key", df, label="Users", ) ``` -------------------------------- ### Table Search Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx Demonstrates how to configure a table with a default search query for 'Urgent customers'. ```typescript const customers = db.selectCompanies(); page.add(() => ui.table("customers-table", customers, { columns: [ "name", "createdAt", "notes" ], // highlight-start views: [ { label: "Urgent customers", description: "Search the table for any row containing the word 'urgent'.", searchQuery: "urgent", } ] // highlight-end })) ``` ```python customers = db.select_companies(); page.add(lambda: ui.table( "customers-table", customers, columns=[ "name", "created_at", "notes" ], # highlight-start views=[ { "label": "Urgent note", "description": "Search the table for any row containing the word 'urgent'.", "search_query": "urgent" ] # highlight-end )) ``` -------------------------------- ### Add starter apps Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/fast-api.mdx Create a new file (e.g., `compose.py`) and paste the starter code for Compose apps. ```python from fastapi import FastAPI from contextlib import asynccontextmanager from .compose import compose_client # Use the `lifespan` context manager to connect to the Compose servers once # when the app starts up, and disconnect when the app shuts down. @asynccontextmanager async def lifespan(app: FastAPI): compose_client.connect_async() yield compose_client.shutdown() app = FastAPI(lifespan=lifespan) ``` -------------------------------- ### Clone the starter repo Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Clones the Python starter repository to begin a new project. ```bash git clone https://github.com/compose-dev/compose-python-starter.git cd compose-python-starter ``` -------------------------------- ### Starter Apps Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/python.mdx Create a new file in your project where you'll add your Compose apps, e.g. `compose.py`, and paste the following code: ```python from compose import ComposeClient compose_client = ComposeClient() # Add your apps here # compose_client.add_app(...) ``` -------------------------------- ### Clone the starter repo Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Clones the Node.js starter repository which includes the Compose SDK. ```bash git clone https://github.com/compose-dev/compose-node-starter.git cd compose-node-starter ``` -------------------------------- ### Validate forms Source: https://github.com/compose-dev/docs/blob/main/docs/guides/forms.mdx Example of using the `validate` hook in a form to implement custom business logic. ```javascript page.add(() => ui.form( "create-user-form", [ ui.radioGroup("role", ["Admin", "User", "Guest"]), ui.numberInput("age"), ], { // highlight-start validate: (form) => { if (form.role === "Admin" && form.age < 18) { // display error to user return "Admins must be at least 18 years old" } return; // or return undefined to indicate no errors }, // highlight-end onSubmit: (form) => createUser(form) } ) ) ``` ```python # highlight-start def validate_form(form): if form["role"] == "Admin" and form["age"] < 18: return "Admins must be at least 18 years old" # display error to user return None # or return None to indicate no errors # highlight-end page.add(lambda: ui.form( "create-user-form", [ ui.radio_group("role", ["Admin", "User", "Guest"]), ui.number_input("age"), ], { # highlight-next-line "validate": validate_form, "on_submit": lambda form: create_user(form) } ) ) ``` -------------------------------- ### Starter Code Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/flask.mdx Create a new file in your project where you'll add your Compose apps, e.g. `compose.py`, and paste the following code: ```python from compose import ComposeClient compose_client = ComposeClient(api_key="YOUR_API_KEY") ``` -------------------------------- ### Upgrade Python SDK using pip Source: https://github.com/compose-dev/docs/blob/main/docs/guides/upgrade-sdk.mdx Installs or upgrades the Compose SDK for Python using pip. ```bash pip install --upgrade compose-sdk ``` -------------------------------- ### Page Update Events Source: https://github.com/compose-dev/docs/blob/main/docs/guides/debug-mode.mdx Example logs showing page update events and their timings, useful for diagnosing slow re-renders. ```log Page event | update | 2025-02-09T10:58:14.286 Page update (fragment: hello-text) event | generated new layout in 0.20 ms | 2025-02-09T10:58:14.288 Page update (fragment: hello-text) event | validated layout in 0.01 ms | 2025-02-09T10:58:14.288 Page update (fragment: hello-text) event | generated diff in 0.10 ms | 2025-02-09T10:58:14.288 Page update (fragment: hello-modal) event | generated new layout in 0.07 ms | 2025-02-09T10:58:14.288 Page update (fragment: hello-modal) event | validated layout in 0.00 ms | 2025-02-09T10:58:14.288 Page update (fragment: hello-modal) event | generated diff in 0.05 ms | 2025-02-09T10:58:14.289 Page update event | computed page diff in 13.08 ms | 2025-02-09T10:58:14.301 Send websocket message event | Rerender UI V2 | 2025-02-09T10:58:14.301 // the event name may be slightly different depending on the SDK ``` -------------------------------- ### Run the app Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/python.mdx Runs the Compose application using py-mon for auto-reloading or directly with Python. ```bash # Use py-mon to enable auto-reload on code changes pymon app.py # Or, use python directly python app.py ``` -------------------------------- ### Upgrade Node.js SDK using npm Source: https://github.com/compose-dev/docs/blob/main/docs/guides/upgrade-sdk.mdx Installs the latest stable version of the Compose SDK for Node.js using npm. ```bash npm install @composehq/sdk@latest ``` -------------------------------- ### Starter code for index.ts Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Starter code for a Node.js application using the Compose SDK, including navigation, app definitions, and client connection. ```typescript import { Compose } from "@composehq/sdk"; const nav = new Compose.Navigation(["view-users", "create-user"]) // For demo purposes. In a real app, you'd use your actual database. const dbUsers = [ { name: "John Doe", email: "john@doe.com" }, { name: "Jane Smith", email: "jane@smith.com" }, ] const viewUsersApp = new Compose.App({ route: "view-users", navigation: nav, handler: async ({ page, ui }) => { page.add(() => ui.header("View Users", { size: "lg" })) const users = [...dbUsers] // fake database call page.add(() => ui.table("users-table", users)); } }) const createUserApp = new Compose.App({ route: "create-user", navigation: nav, handler: async ({ page, ui }) => { page.add(() => ui.header("Create User", { size: "lg" })) page.add(() => ui.form( "create-user-form", [ ui.textInput("name"), ui.emailInput("email") ], { onSubmit: async (form) => { dbUsers.push({ name: form.name, email: form.email }); page.toast("User created successfully", { appearance: "success" }); page.link("view-users"); } } )) } }) const client = new Compose.Client({ apiKey: "API_KEY_HERE", // replace with your own API key apps: [viewUsersApp, createUserApp] }); client.connect(); ``` -------------------------------- ### Statistic examples Source: https://github.com/compose-dev/docs/blob/main/docs/components/display/statistic.mdx Examples of how to use the Statistic component in TypeScript/JavaScript and Python. ```typescript ui.row([ ui.statistic( "Total Users", 135, { delta: 14, description: "Since last month", format: "currency", }, ), ui.statistic( "Total Revenue", 39211, { format: "currency", delta: .06, deltaFormat: "percent", description: "Since last month", }, ), ui.statistic( "At Risk Accounts", 12, { delta: -1, isPositiveDelta: true, description: "Since last month", labelColor: "danger", }, ), ]) ``` ```python ui.row([ ui.statistic( "Total Users", 135, delta=14, description="Since last month", format="currency" ), ui.statistic( "Total Revenue", 39211, format="currency", delta=0.06, delta_format="percent", description="Since last month" ), ui.statistic( "At Risk Accounts", 12, delta=-1, is_positive_delta=True, description="Since last month", label_color="danger" ) ]) ``` -------------------------------- ### Build the docs Source: https://github.com/compose-dev/docs/blob/main/README.md Instructions to build the documentation website. ```bash pnpm build ``` -------------------------------- ### Row component example Source: https://github.com/compose-dev/docs/blob/main/docs/components/layout/row.mdx This example shows how to create a row component with three buttons. ```js ui.row([ ui.button("view-btn", { label: "View" }), ui.button("edit-btn", { label: "Edit", appearance: "outline" }), ui.button("delete-btn", { label: "Delete", appearance: "danger" }) ]) ``` ```python ui.row([ ui.button("view-btn", label="View"), ui.button("edit-btn", label="Edit", appearance="outline"), ui.button("delete-btn", label="Delete", appearance="danger") ]) ``` -------------------------------- ### Run the docs locally Source: https://github.com/compose-dev/docs/blob/main/README.md Instructions to run the documentation website locally. ```bash pnpm start ``` -------------------------------- ### Initialize project and set type to module Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/new-project/node-js.mdx Initializes a new Node.js project and sets the project type to 'module' for modern JavaScript syntax. ```bash npm init -y && npm pkg set type=module ``` -------------------------------- ### Column Overrides Example Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx Example of how to override the pinned and hidden properties of table columns for a specific view. ```js { name: { pinned: "left" }, uuid: { hidden: false } } ``` ```python { "name": { "pinned": "left" }, "uuid": { "hidden": False } } ``` -------------------------------- ### TypeScript/JavaScript Example: Single Filter Rule Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx This example demonstrates how to apply a single filter rule to a table column. ```typescript const customers = db.selectCompanies(); page.add(() => ui.table("customers-table", customers, { columns: [ "name", "createdAt", "onboardingComplete", { key: "plan", format: "tag" }, { key: "arr", format: "currency" }, ], views: [ { label: "Enterprise Customers", // highlight-start // Example 1: Apply a single filter rule. filterBy: { key: "plan", operator: "hasAny", value: ["Enterprise"] }, // highlight-end }, { label: "Urgent Customers", // highlight-start // Example 2: A complex nested filter group. filterBy: { logicalOperator: "and", filters: [ { key: "plan", operator: "hasAny", value: ["Enterprise"] }, { logicalOperator: "or", filters: [ { key: "arr", operator: "greaterThan", value: 1000 }, { key: "onboardingComplete", operator: "is", value: false } ] } ] } // highlight-end }, ] })) ``` -------------------------------- ### Python Example: Single Filter Rule Source: https://github.com/compose-dev/docs/blob/main/docs/components/input/table.mdx This example demonstrates how to apply a single filter rule to a table column in Python. ```python customers = db.select_companies(); page.add(lambda: ui.table( "customers-table", customers, columns=[ "name", "created_at", "onboarding_complete", { "key": "plan", "format": "tag" }, { "key": "arr", "format": "currency" }, ], views=[ { "label": "Enterprise Customers", # highlight-start # Example 1: Apply a single filter rule. "filter_by": { "key": "plan", "operator": "has_any", "value": ["Enterprise"] }, # highlight-end }, { "label": "Urgent Customers", # highlight-start # Example 2: A complex nested filter group. "filter_by": { "logical_operator": "and", "filters": [ { "key": "plan", "operator": "has_any", "value": ["Enterprise"] }, { "logical_operator": "or", "filters": [ { "key": "arr", "operator": "greater_than", "value": 1000 }, { "key": "onboarding_complete", "operator": "is", "value": False } ] } ] }, # highlight-end }, ] )) ``` -------------------------------- ### Initialize Compose Client Source: https://github.com/compose-dev/docs/blob/main/docs/get-started/installation/fastify.mdx In the main entry point of your project, e.g. `index.ts`, import the Compose Client that you exported in the previous step and initialize it: ```typescript // highlight-start import { composeClient } from "./compose"; // highlight-end // ... fastify.listen({ port: 3000 }, (err, address) => { if (err) { fastify.log.error(err); process.exit(1); } fastify.log.info(`server listening on ${address}`); // highlight-start composeClient.connect(); // highlight-end }); ```