### 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
});
```