New Component: streamlit-shadcn-ui, using modern ui components to build data app

Hi developers, I just created a new component: streamlit-shadcn-ui It allows streamlit developers to use one of the most popular frontend components library shadcn to build streamlit data apps. Interested in any feedback (especially for experimental features like nest component)

Main features you can benefit from it:

  • Extends the options of components (with minimalism style of design) for building data app, (modal, hovercard, badges, etc)
  • Customization of UI design: it allows you to write tailwind CSS to adjust the design.
  • Nest component, it provide a basic element component, which supports multi-level components nesting to build more complex layouts.

Github: GitHub - ObservedObserver/streamlit-shadcn-ui: Using shadcn-ui components in streamlit


That’s really neat, thanks @ObservedObserver for creating this!


This is very similar to the style of streamlit, I really like it, especially the pop-up box. :smiling_face_with_three_hearts:


This is a nice library.

I see there is class_name in button.

ui.button("Click", key="clk_btn")

How to use the class_name? Does it support tailwind?

Streamlit really needs styling supports.

1 Like

Currently, only the element function allows for styling components with either style or className (using Tailwind). This feature is still experimental, but I plan to complete most of the work this week. For example:

import streamlit_shadcn_ui as ui

with ui.card(key="card1"):
    ui.element("span", children=["Email"], className="text-gray-400 text-sm font-medium m-1", key="label1")
    ui.element("input", key="email_input", placeholder="Your email")

    ui.element("span", children=["User Name"], className="text-gray-400 text-sm font-medium m-1", key="label2")
    ui.element("input", key="username_input", placeholder="Create a User Name")
    ui.element("button", text="Submit", key="button", className="m-1")

One concern I have is preventing the frontend application from becoming too bulky. Each iframe incorporating its own complete bundle of Tailwind code could lead to excessively large files. Full Tailwind integration offers a great development experience, but at the cost of increased bundle size, which is particularly significant since a Streamlit app typically contains many iframe-based components.

To address this, I am considering offering two initial options: including the complete Tailwind style by default, but also providing a ‘lite-mode’ with limited Tailwind for those who prefer a leaner approach.

Another task to complete before making element a formal feature involves the handling of element values. When using nested elements, they share the same iframe and Streamlit values in the session state. Therefore, I need to slightly refactor the current value type to include the component key, allowing all components to share a single Streamlit value.


This is really awesome. …

Because of my basic knowledge, I have 2 questions:

  1. Would all the components listed in Accordion - shadcn/ui be available to streamlit?
  2. Would I be able to create something like Tasks ( with streamlit?


1 Like
  1. Yes, I am planning to add them all, now it has
  • button
  • checkbox
  • select
  • tabs
  • card
  • avatar
  • date_picker
  • table
  • input
  • slider
  • textarea
  • switch
  • radio_group
  • alert_dialog
  • hover_card
  • badges
  • link_button

You can raise a issue in the github if you want some components that have not been built yet.

  1. Sure, ‘Task’ is mainly the data type, which is something I am working on with high priority.

This is amazing. Congratulations on the great work! Its a very powerful component

If you accept suggestions, I would suggest making background colors transparent in some components. This makes it more flexible to use the component along with CSS changes in the app.


Thanks for your feedback, I will expose the theme system of shadcn soon, which allow developers to customize the theme and global styles.


First off, I think this is fantastic!

Second, I haven’t taken a look at the code, but I imagine it should be possible to add wrapper functions in the python script so that specific elements can be called as follows:

with ui.card(key="card1"):
    ui.span(children=["Email"], className="text-gray-400 text-sm font-medium m-1", key="label1")
    ui.input(key="email_input", placeholder="Your email")
    # etc..

where each of those element functions just pass the arguments to ui.element. Something like:

def span(**kwargs):
    element("span", **kwargs)

This way its not a breaking change because users can still use the ui.element function


I love designs/front-end.

WIll give it a try on my personal project soon

1 Like

Hi @ObservedObserver great library!

I am using this simple code

import streamlit_shadcn_ui as ui
import streamlit as st

trigger_btn = ui.button(text="Trigger Button", key="trigger_btn_1")
ui.alert_dialog(show=trigger_btn, title="Alert Dialog", description="This is an alert dialog", confirm_label="OK", cancel_label="Cancel", key="alert_dialog_1")

I am getting this error:

TypeError: 'type' object is not subscriptable
File "C:\Users\XXX\miniconda3\envs\streamlit_1_25\lib\site-packages\streamlit\runtime\scriptrunner\", line 552, in _run_script
    exec(code, module.__dict__)
File "C:\XXXX\", line 1, in <module>
    import streamlit_shadcn_ui as ui
File "C:\Users\XXXX\miniconda3\envs\streamlit_1_25\lib\site-packages\streamlit_shadcn_ui\", line 4, in <module>
    from .py_components import *
File "C:\Users\XXXX\miniconda3\envs\streamlit_1_25\lib\site-packages\streamlit_shadcn_ui\py_components\", line 3, in <module>
    from .select import select
File "C:\Users\XXX\miniconda3\envs\streamlit_1_25\lib\site-packages\streamlit_shadcn_ui\py_components\", line 14, in <module>
    def select_options(options: list[str], x, y, open_status=False, key=None, default_value=None, on_change=None, args=None, kwargs=None):

Do you have any idea why this is throwing this error?

1 Like

@ObservedObserver I’ve answered my own problem: this error is thrown because I am using a version of Python older than 3.9. I will upgrade my Python version and see how that goes


How do I add the download function to my UI.element? For example, I created the following code:
def filedownload(df):
csv = df.to_csv(index=False)
b64 = base64.b64encode(csv.encode()).decode() # strings ↔ bytes conversions
href=f’Download CSV File
return href

1 Like

this is fantastic, and thank you very much for this, we can really leverage one of the greatest frontend UI framwork easily into Streamlit, this is truly helpful for data scientists who wants to build beatiful data app!!!

1 Like

looks awesome, the metric cards really pop

1 Like

@ObservedObserver How do I add the download function to my UI.element? For example, I created the following code:
def filedownload(df):
csv = df.to_csv(index=False)
b64 = base64.b64encode(csv.encode()).decode() # strings ↔ bytes conversions
href=f’Download CSV File’
return href

1 Like

I am also facing same trouble in my application. Is there any solution?

1 Like

Unfortunately, I think it was a streamlit thing. Many of my components that I used with transparent backgrounds no longer work the same way :confused:

1 Like

Hi, is there a way to display buttons within the ui tables?

1 Like