Code snippet: create Components without any frontend tooling (no React, Babel, Webpack, etc)

Right.
Did the same.
Thanks
Michel

Hi, Thiago! What if I want to fill my index.html with jinja at first and then render it?

If you only need to do that once, then you can just render your jinja template and save to disk as index.html

Otherwise, if you need it to be dynamic, you could wrap your Python component in a function that calls mycomponent(html=my_rendered_jinja_template) to send the rendered jinja HTML to a dummy index.html that just replaces some div’s .innerHTML with it.

(I’m not able to write example code right now, but that’s the gist of it!)

3 Likes

Elegant use of postMessage between iframe child and parent! What an idea!

1 Like

Hello everyone.
I’m trying to add a Mapbox’s geolocator (link) into my streamlit app but I’m struggling to get the json value and send it back to python.
Any advice ?

I’m using this method and it works well. However, I can’t seem to load local videos on my HTML file with proper controls. I’ve tried (Restrict Download of Images & Videos on Streamlit App - #2 by andfanilo) but it does not seem to be able to load from the static folder. Anyone know how to resolve this?

Hi @thiago , that’s very insightful!

I am currently playing with it and one piece I miss is how a state of component can be saved / loaded? I want my component to behave like built-in.

I think in your example component just ignores the changes and gets user input, correct?

oh, I think I realized how that works, streamlit just keeps iframe around until it is not used

Hi @thiago , here’s a rookie asking a few questions:

  1. Is it possible to program a dropdown / selectbox this way, where elements need to be taken from a CSV (or even a small set of elements)? How would I pass them from Streamlit to HTML
  2. I guess that something resembling a form can be done, but with a collection of individual components, right?
  3. How could we add other features to this type of programming. eg. Date Picker?

Wouldn’t entry widgets created this way process faster than if they were done the normal way with Streamlit (because of the reload)? I mean, if your entry screen had a large number of widget… say 40… (along with dependencies), Streamlit would slow down to a crawl, but not if you program it this way, right?

Thanks in advance.

Cheers

Hi. Is there a way to avoid having a separate HTML file, by just providing its content as a string to declare_component instead of the path parameter?

Out of context of this post, but you can load an html string into components.iframe like this:

raw_html = ''' ... some html ... '''
b64_html = base64.b64encode(raw_html).decode()
src = f"data:text/html;base64,{b64_html}"
components.iframe(src=src, width=1100, height=1200, scrolling=True)
1 Like

Ingenius idea! I assume it works anywhere a URL is expected, right?

Yes, just change the mime type (data). I haven’t tested all variations.

For the record, this didn’t work with declare_component. Maybe because it is expected that something is served? :-/

1 Like

Hi @thiago, Thanks for this code snippet
I just need the screen width and height to use in my application. This functionality seems to be helping my case.
I changed the code piece in index.html.

  // data is any JSON-serializable value you sent from Python,
  // and it's already deserialized for you.
  function onDataFromPython(event) {
    var width = window.screen.width
    var space = " "
    var height = window.screen.height
    if (event.data.type !== "streamlit:render") return;
    // myInput.value = event.data.args.my_input_value;  // Access values sent from Python here!
    myInput.value = [width, height]
  }

image
and I am getting this output. I dont want the message to be displayed in text input rather need width and height as a variable in backend python. the value is always None. What should I do for my request. Please guide

1 Like

@Murugan_Yuvaraaj_M_P Are you calling sendDataToPython in your script anywhere? That’s what you’ll need to call in order to send the data back to your python script.

If you’re interested, I created a cookiecutter template for creating a component that uses a slightly modified version of Thiago’s snippet and wrote a blog post showing how to use it How to build your own Streamlit component

1 Like

Thanks for the example. However whenever i add a
<script src='some_external.js' />
I get the following error:

The app is attempting to load the component from ****, and hasn't received its "streamlit:componentReady" message

Would appreciate any help in this. I am including an external js and do not want to paste it verbatim in <script>

In addition to @thiago’s and @blackary’s articles I wrote one which starts from the very basics and progresses towards a full blown React / Next.js component design. You can read up to the end of section “Component Zero”.

3 Likes

@thiago how can I add a simple React component into mycomponent/index.html ? do you have an example? Thanks in advance

UPDATE: please ignore my message, i was able to do it. Thanks again :pray:

hey @thiago, this is really cool, thanks a lot for sharing.
I am trying to have a clickable list of items so wanted to slightly alter your example with the click event and it looks like it somehow triggers twice so the variable is reset. Any idea how to prevent that?
The same is happening to the click detector lib, and it looks like more people have experienced this. Duplication when clicking · Issue #9 · vivien000/st-click-detector · GitHub
this is all i added to your code, and its still working fine with the change event.

       <div id="justadiv">hohoho</div>
        var justadiv = document.getElementById("justadiv");

      justadiv.addEventListener("click", function() {
        sendDataToPython({
          value: myInput.value,
          dataType: "json",
        });
      })