@stlite/browser
@stlite/browser allows you to mount a Streamlit app on a static web page using a <script> tag.
Installation & Usage
Section titled “Installation & Usage”You can use Stlite on your web page by loading the JavaScript and CSS files via <script> and <link> tags.
Using <streamlit-app> tag
Section titled “Using <streamlit-app> tag”The easiest way is using the <streamlit-app> custom element.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Custom Element</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> <script type="module" src="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.js"></script> </head> <body> <streamlit-app>import streamlit as st
st.title("Custom Element Test")
option = st.selectbox( 'How would you like to be contacted?', ('Email', 'Home phone', 'Mobile phone'))
st.write('You selected:', option) </streamlit-app> </body></html>Loading from an external file
Section titled “Loading from an external file”You can load the app from an external Python file using the src attribute:
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Source Attribute</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> <script type="module" src="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.js"></script> </head> <body> <streamlit-app src="./app.py"></streamlit-app> </body></html>The filename is extracted from the URL path (e.g., ./app.py becomes app.py in the virtual filesystem).
You can also combine the src attribute with child elements to add additional files and requirements:
<streamlit-app src="./main.py"> <app-file name="utils.py" url="./utils.py"></app-file> <app-requirements> numpy pandas </app-requirements></streamlit-app>Using mount() function
Section titled “Using mount() function”For more control, you can use the mount() function.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Basic Mount</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> </head> <body> <div id="root"></div> <script type="module"> window.controller = mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `import streamlit as st
st.title("Stlite Browser Test")name = st.text_input('Your name')st.write("Hello,", name or "world")`, }, }, document.getElementById("root"), ); </script> </body></html>Advanced Features
Section titled “Advanced Features”Multipage apps
Section titled “Multipage apps”You can create multipage apps by mounting multiple files, including an entrypoint and page files in a pages/ directory.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Multipage App</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> </head> <body> <div id="root"></div> <script type="module"> mount( { entrypoint: "Hello.py", files: { "Hello.py": `import streamlit as st
st.title("Main page")st.write("Welcome to the multipage app demo!")st.write("Use the sidebar to navigate between pages.")`, "pages/1_Page1.py": `import streamlit as st
st.title("Page 1")st.write("This is the first page.")`, "pages/2_Page2.py": `import streamlit as st
st.title("Page 2")st.write("This is the second page.")`, }, }, document.getElementById("root"), ); </script> </body></html>Installing Packages
Section titled “Installing Packages”Use the requirements option to install Python packages.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Requirements</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> </head> <body> <div id="root"></div> <script type="module"> mount( { requirements: ["faker"], entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `import streamlit as stfrom faker import Faker
# Set seed for deterministic output (useful for testing)Faker.seed(12345)fake = Faker()
st.title("Requirements Demo")st.write("This demo shows how to install Python packages.")
st.subheader("Faker Examples")
st.write("Name: " + fake.name())st.write("Email: " + fake.email())st.write("Address: " + fake.address().replace("\\n", ", "))st.write("Company: " + fake.company())`, }, }, document.getElementById("root"), ); </script> </body></html>Multiple Apps on a Single Page
Section titled “Multiple Apps on a Single Page”You can mount multiple independent Stlite apps on the same page by calling mount() multiple times with different container elements. By default, each app runs in its own Web Worker with isolated session state.
When embedding multiple apps, set disableDocumentStyles: true to prevent each app from injecting global document styles that could conflict with each other or with your page layout.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Multi App</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> <style> html, body { width: 100%; height: 100%; margin: 0; padding: 0; } .container { display: flex; gap: 16px; width: 100%; height: 100%; } .app { position: relative; flex: 1; } </style> </head> <body> <div class="container"> <div id="app1" class="app"></div> <div id="app2" class="app"></div> </div> <script type="module"> mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `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}")`, }, disableDocumentStyles: true, }, document.getElementById("app1"), ); mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `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}")`, }, disableDocumentStyles: true, }, document.getElementById("app2"), ); </script> </body></html>You can also combine multiple apps with sharedWorker: true so they share a single Python worker, reducing memory usage while keeping session state independent.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - Multi App SharedWorker</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> <style> html, body { width: 100%; height: 100%; margin: 0; padding: 0; } .container { display: flex; gap: 16px; width: 100%; height: 100%; } .app { position: relative; flex: 1; } </style> </head> <body> <div class="container"> <div id="app1" class="app"></div> <div id="app2" class="app"></div> </div> <script type="module"> mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `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}")`, }, sharedWorker: true, disableDocumentStyles: true, }, document.getElementById("app1"), ); mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `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}")`, }, sharedWorker: true, disableDocumentStyles: true, }, document.getElementById("app2"), ); </script> </body></html>Persistent Storage with IDBFS
Section titled “Persistent Storage with IDBFS”By default, the virtual file system is in-memory and lost on page reload. Use the idbfsMountpoints option to mount directories backed by IndexedDB, so files persist across page reloads.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - IDBFS Persistent Storage</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> </head> <body> <div id="root"></div> <script type="module"> mount( { entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `import streamlit as st
st.title("IDBFS Persistent Storage")st.write("Data written to \`/mnt\` persists across page reloads using IndexedDB.")
try: with open("/mnt/counter.txt", "r") as f: count = int(f.read())except (FileNotFoundError, ValueError): count = 0
count += 1
with open("/mnt/counter.txt", "w") as f: f.write(str(count))
st.write(f"Visit count: {count}")
if st.button("Reset counter"): with open("/mnt/counter.txt", "w") as f: f.write("0") st.rerun()`, }, idbfsMountpoints: ["/mnt"], }, document.getElementById("root"), ); </script> </body></html>SharedWorker Mode
Section titled “SharedWorker Mode”To reduce memory consumption when running multiple Stlite apps, enable SharedWorker mode.
<!doctype html><html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Stlite Demo - SharedWorker</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stlite/[email protected]/build/stlite.css" /> </head> <body> <div id="root"></div> <script type="module"> mount( { sharedWorker: true, entrypoint: "streamlit_app.py", files: { "streamlit_app.py": `import streamlit as st
st.title("SharedWorker Demo")st.write("This app runs in SharedWorker mode.")st.write("Multiple Stlite apps can share the same Python worker to reduce memory usage.")
if "count" not in st.session_state: st.session_state.count = 0
if st.button("Click me"): st.session_state.count += 1
st.write(f"Button clicked {st.session_state.count} {'time' if st.session_state.count == 1 else 'times'}")`, }, }, document.getElementById("root"), ); </script> </body></html>API Reference
Section titled “API Reference”mount(options, container)
Section titled “mount(options, container)”Mounts the Streamlit app to the given HTML container.
Parameters:
options:object|string- If a string is provided, it is treated as the content of the
streamlit_app.pyfile. - If an object is provided, it must be a
MountOptionsobject (see below).
- If a string is provided, it is treated as the content of the
container:HTMLElement(optional, default:document.body)- The DOM element to mount the app into.
Returns:
A StliteController object with the following methods:
unmount(): Unmounts the app and disposes the kernel.install(requirements): Installs additional packages.writeFile(path, data, opts): Writes a file to the virtual filesystem.readFile(path, opts): Reads a file from the virtual filesystem.unlink(path): Deletes a file.renameFile(oldPath, newPath): Renames a file.
MountOptions
Section titled “MountOptions”Configuration object for mount().
| Property | Type | Description |
|---|---|---|
entrypoint | string | The file path of the main script (e.g., "streamlit_app.py"). Required if files is an object. |
files | Record<string, FileContent> | An object mapping file paths to their content. Content can be a string, Uint8Array, or an object { url: string }. |
requirements | string[] | A list of Python packages to install at startup. |
streamlitConfig | Record<string, any> | Streamlit configuration options (e.g., { "client.toolbarMode": "viewer" }). |
archives | ArchiveObject[] | List of archive files (e.g., zip) to download and unpack. |
pyodideUrl | string | Custom URL for the Pyodide interpreter. |
sharedWorker | boolean | Whether to use a SharedWorker. |
idbfsMountpoints | string[] | List of paths to mount with IDBFS (IndexedDB-based persistent file system). |
<streamlit-app> Custom Element
Section titled “<streamlit-app> Custom Element”The <streamlit-app> custom element provides a declarative way to embed Streamlit apps.
Attributes
Section titled “Attributes”| Attribute | Description |
|---|---|
src | URL to load the main Python file from. The filename is extracted from the URL path. |
shared-worker | Enable SharedWorker mode for reduced memory usage. |
Child Elements
Section titled “Child Elements”| Element | Description |
|---|---|
<app-file name="..." [url="..."] [entrypoint]> | Define a file. Use url to load from URL, or place content inside the tag. Add entrypoint to mark as the main script. |
<app-requirements> | List Python packages to install (one per line, like requirements.txt). |
<app-archive url="..." format="..."> | Load and unpack an archive file (zip, tar.gz). |
Usage Modes
Section titled “Usage Modes”-
Inline code: Place Python code directly inside
<streamlit-app>:<streamlit-app>import streamlit as stst.write("Hello")</streamlit-app> -
External file via
src: Load from a URL:<streamlit-app src="./app.py"></streamlit-app> -
Child elements: Use
<app-file>withentrypointattribute:<streamlit-app><app-file name="app.py" entrypoint>import streamlit as stst.write("Hello")</app-file></streamlit-app>