Skip to content

@stlite/react

@stlite/react provides React bindings for running Streamlit entirely in the browser with Stlite. It connects the Pyodide-backed kernel to the Streamlit UI.

Terminal window
npm install @stlite/react

Update vite.config.ts to add the helper plugin so some assets are bundled correctly. Import stliteReactPlugin from @stlite/react/vite-plugin.

vite.config.ts
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import stliteReactPlugin from "@stlite/react/vite-plugin";
export default defineConfig({
plugins: [react(), stliteReactPlugin()],
});

Create a kernel, pass the bundled wheel URLs, and render the app.

App.tsx
import { StliteAppWithToast, createKernel } from "@stlite/react";
import { wheelUrls } from "@stlite/react/vite-utils";
const kernel = createKernel({
entrypoint: "app.py",
files: {
"app.py": {
data: `
import streamlit as st
st.title("Hello, Stlite!")
st.write("This app runs entirely in your browser.")
name = st.text_input("Your name")
if name:
st.write(f"Hello, {name}!")
`,
},
},
requirements: [],
prebuiltPackageNames: [],
archives: [],
wheelUrls,
});
export function App() {
return <StliteAppWithToast kernel={kernel} />;
}

You can run multiple Stlite apps on the same page by creating separate kernel instances.

MultiApp.tsx
import { StliteAppWithToast, createKernel } from "@stlite/react";
import { wheelUrls } from "@stlite/react/vite-utils";
const kernel1 = createKernel({
entrypoint: "app.py",
files: {
"app.py": {
data: `
import streamlit as st
st.write("Hello, stlite!")
st.write("App 1")
if "counter" not in st.session_state:
st.session_state.counter = 0
if st.button("Increment counter"):
st.session_state.counter += 1
st.write(f"Counter: {st.session_state.counter}")
`,
},
},
requirements: [],
prebuiltPackageNames: [],
archives: [],
wheelUrls,
});
const kernel2 = createKernel({
entrypoint: "app.py",
files: {
"app.py": {
data: `
import streamlit as st
st.write("Hello, stlite!")
st.write("App 2")
if "counter" not in st.session_state:
st.session_state.counter = 0
if st.button("Increment counter"):
st.session_state.counter += 1
st.write(f"Counter: {st.session_state.counter}")
`,
},
},
requirements: [],
prebuiltPackageNames: [],
archives: [],
wheelUrls,
});
export function App() {
return (
<div style={{ width: "100%", height: "100%", display: "flex", gap: 16 }}>
<div style={{ position: "relative", flex: 1 }}>
<StliteAppWithToast kernel={kernel1} disableDocumentStyles />
</div>
<div style={{ position: "relative", flex: 1 }}>
<StliteAppWithToast kernel={kernel2} disableDocumentStyles />
</div>
</div>
);
}

When running multiple apps, you can enable SharedWorker mode to reduce memory usage. In this mode, all apps share a single Pyodide worker instead of each having their own.

SharedWorkerApp.tsx
import { StliteAppWithToast, createKernel } from "@stlite/react";
import { wheelUrls } from "@stlite/react/vite-utils";
// Create kernels with sharedWorker: true to share a single worker between apps.
// This reduces memory usage when running multiple apps on the same page.
// Note: SharedWorker shares the Python runtime, but each app has its own
// independent session state. Data is NOT shared between apps.
// Note: SharedWorker is not supported in all browsers (e.g., Chrome Android).
const kernel1 = createKernel({
entrypoint: "app.py",
files: {
"app.py": {
data: `
import streamlit as st
st.write("Hello, stlite!")
st.write("Shared Worker App 1")
if "counter" not in st.session_state:
st.session_state.counter = 0
if st.button("Increment counter"):
st.session_state.counter += 1
st.write(f"Counter: {st.session_state.counter}")
`,
},
},
requirements: [],
prebuiltPackageNames: [],
archives: [],
wheelUrls,
sharedWorker: true,
});
const kernel2 = createKernel({
entrypoint: "app.py",
files: {
"app.py": {
data: `
import streamlit as st
st.write("Hello, stlite!")
st.write("Shared Worker App 2")
if "counter" not in st.session_state:
st.session_state.counter = 0
if st.button("Increment counter"):
st.session_state.counter += 1
st.write(f"Counter: {st.session_state.counter}")
`,
},
},
requirements: [],
prebuiltPackageNames: [],
archives: [],
wheelUrls,
sharedWorker: true,
});
export function App() {
return (
<div style={{ width: "100%", height: "100%", display: "flex", gap: 16 }}>
<div style={{ position: "relative", flex: 1 }}>
<StliteAppWithToast kernel={kernel1} disableDocumentStyles />
</div>
<div style={{ position: "relative", flex: 1 }}>
<StliteAppWithToast kernel={kernel2} disableDocumentStyles />
</div>
</div>
);
}

A wrapper around <StliteApp /> that includes toast notifications for:

  • Loading progress
  • Errors
  • Module auto-loading

Props:

  • kernel: StliteKernel - The kernel instance created with createKernel.
  • disableDocumentStyles: boolean (optional, default: false) - Whether to disable global document styles.
  • disableProgressToasts: boolean (optional)
  • disableErrorToasts: boolean (optional)
  • disableModuleAutoLoadToasts: boolean (optional)

The core component that renders the Streamlit app UI. It does not show any toast notifications.

Props:

  • kernel: StliteKernel - The kernel instance.
  • disableDocumentStyles: boolean (optional, default: false) - Whether to disable global document styles.

Creates a new StliteKernel instance.

Key Options:

  • entrypoint: string - The main Python file to run.
  • files: Record<string, FileContent> - Virtual file system contents.
  • requirements: string[] - Python packages to install via micropip.
  • wheelUrls: WheelUrls - Wheel URLs from @stlite/react/vite-utils.
  • sharedWorker: boolean (optional) - Enable SharedWorker mode for reduced memory when running multiple apps.

See the StliteKernelOptions in @stlite/browser documentation for the complete list of options.