Vite + Streamlit: How to develop custom components

The way to develop new streamlit component sue Vanilla Java Script with vite

Nicola Landro
3 min readJul 1, 2023

For deveoping custom streamlit component the official guide show how to made with react and it si also abit old configuration. There is that new guide that explain how to use vanilla javascript with vite and use the vite cli that is a very beatufull way to start a node project.

In this guide we will see step by step how to to create the custom streamlit component to the deploy on pypi repo or gitlab one.

An example of pypi deployed streamlit vanillajs component

Prerequirements

We need to setup python3.10 and node 18.x on the computer before working.

I will use pip and venv for python and npm for nodejs.

Overview of Folder structure

Firs of all the folder structure will be created in the same way:

/repofolder
component_name/
frontend/
vite project...
__init__.py
pypi_readme.md
MANIFEST.in
build.py

Create Frontend

Create component folder and put the frontend code

mkdir component_name
cd component_name
npm init vite@latest frontend --template vanilla

Create vite.config.js

export default {
base: './'
}

Replace The main.js

import { Streamlit } from "streamlit-component-lib"

const span = document.body.appendChild(document.createElement("span"))
const textNode = span.appendChild(document.createTextNode(""))
const button = span.appendChild(document.createElement("button"))
button.textContent = "Click Me!"

let numClicks = 0
let isFocused = false
button.onclick = function() {
numClicks += 1
Streamlit.setComponentValue(numClicks)
}

button.onfocus = function() { isFocused = true }
button.onblur = function() { isFocused = false }

function onRender(event) {
const data = event.detail
if (data.theme) {
const borderStyling = `1px solid var(${
isFocused ? "--primary-color" : "gray"
})`
button.style.border = borderStyling
button.style.outline = borderStyling
}
button.disabled = data.disabled
let name = data.args["name"]
textNode.textContent = `Hello, ${name}! ` + String.fromCharCode(160)
Streamlit.setFrameHeight()
}

Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRender)
Streamlit.setComponentReady()
Streamlit.setFrameHeight()

And run frontend:

cd component_name/frontend
npm install
npm i streamlit-component-lib
npm run dev

Python code

Now you can create inside the component_name folder the __init__.py

import os
import streamlit.components.v1 as components

_RELEASE = False

if not _RELEASE:
_component_func = components.declare_component(
"vite_vanilla_component",
url="http://localhost:5173", # vite dev server port
)
else:
parent_dir = os.path.dirname(os.path.abspath(__file__))
build_dir = os.path.join(parent_dir, "frontend/dist")
_component_func = components.declare_component("vite_vanilla_component", path=build_dir)

def my_component(name, key=None):
component_value = _component_func(name=name, key=key, default=0)
return component_value

if not _RELEASE:
import streamlit as st
st.subheader("Component Test")
num_clicks = my_component(name = "NameViteVanilla")
st.markdown("You've clicked %s times!" % int(num_clicks))

You can create venv install libs and run the server

python3.10 -m venv venv
source venv/bin/activate #or source venv/bin/activate.fish for fish shell
pip install streamlit

streamlit run component_name/__ini__.py

Now you are ready do develop new custom streamlit plugin.

Configure For build

To build a python libs we need a Setup.py

import setuptools

import os
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'component_name/pypi_readme.md'), 'r') as f:
long_des = f.read()

setuptools.setup(
name="component-name",
version="0.0.1",
author="Name Surname",
author_email="mail94@mail.it",
description="This library is a streamlit app for...",
long_description=long_des,
long_description_content_type="text/markdown",
url="https://siteurl...",
keywords = ['some', 'key', 'word'],
project_urls={
'Source': 'https://githuburl...',
},
packages=setuptools.find_packages(),
include_package_data=True,
classifiers=[],
python_requires=">=3.6",
install_requires=[
# By definition, a Custom Component depends on Streamlit.
# If your component has other Python dependencies, list
# them here.
"streamlit >= 0.63",
],
)

And a readme for the pypi description in component_name/pypi_readme.md:

# Component Name
This component is...

To install:

```
pip install component_name
```

Example to use:

```
import component_name

component_name...
```

Now you can login in pypi and configure the ~/.pypirc file

[pypi]
repository=https://upload.pypi.org/legacy/
username = __token__
password = <token>

Now you can use twine for build frontend:

cd component_name/frontend
# clean rm -rf dist
npm run build

Specify MANIFEST.in for the files to include in the lib

recursive-include component_name/frontend/dist *
include component_name/pypi_readme.md

Change on __init__.py

_RELEASE = True

(remember to change the version on setup.py)

Build python app

# clean rm -rf dist
python setup.py sdist

Install twine check and upload

pip install twine
twine check dist/*
twine upload dist/*

Now you have your lib on pypi!

Conclusions

To see furthermore things you can create automatic building pipeline for deploy. An example of an app maded as described here is streamlit_seqviz to see one deployed lib.

So enjoy publishing your own custom plugin and contribute to open source!

--

--

Nicola Landro

Linux user and Open Source fun. Deep learning PhD. , Full stack web developer, Mobile developer, cloud engineer and Musitian.