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

We never properly documented this, but you can actually create Components in a super scrappy way using nothing but a static HTML file!

Here’s how:

mycomponent/index.html

<html>
  <body>
    <!-- Set up your HTML here -->
    <input id="myinput" value="" />

    <script>
      // ----------------------------------------------------
      // Just copy/paste these functions as-is:

      function sendMessageToStreamlitClient(type, data) {
        var outData = Object.assign({
          isStreamlitMessage: true,
          type: type,
        }, data);
        window.parent.postMessage(outData, "*");
      }

      function init() {
        sendMessageToStreamlitClient("streamlit:componentReady", {apiVersion: 1});
      }

      function setFrameHeight(height) {
        sendMessageToStreamlitClient("streamlit:setFrameHeight", {height: height});
      }

      // The `data` argument can be any JSON-serializable value.
      function sendDataToPython(data) {
        sendMessageToStreamlitClient("streamlit:setComponentValue", data);
      }

      // ----------------------------------------------------
      // Now modify this part of the code to fit your needs:

      var myInput = document.getElementById("myinput");

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

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

      // Hook things up!
      window.addEventListener("message", onDataFromPython);
      init();

      // Hack to autoset the iframe height.
      window.addEventListener("load", function() {
        window.setTimeout(function() {
          setFrameHeight(document.documentElement.clientHeight)
        }, 0);
      });

      // Optionally, if the automatic height computation fails you, give this component a height manually
      // by commenting out below:
      //setFrameHeight(200);
    </script>
  </body>
</html>

mycomponent/__init__.py

import streamlit.components.v1 as components
mycomponent = components.declare_component(
    "mycomponent",
    path="./mycomponent"
)

And you’re done!


How to use this:

import streamlit as st
from mycomponent import mycomponent
value = mycomponent(my_input_value="hello there")
st.write("Received", value)
9 Likes

2 Likes

Hello! Very interresting!
But I need help!

Unfortunately, I was not able to run this example.
This gets displayed on my app screen:

Capture

The files tree of my tiny project is as follows:

psychroST
… psychroST.py
… psychroST
… … __init__.py
… … chart.py
… … process.py
… mycomponent
… … __init__.py
… … index.html

The two last files are from your post.
My app script (psychroST.py) contains these lines:

from mycomponent import *

value = mycomponent.example(my_input_value=“hello there”)
st.write(“Received”, value)

Thanks for your suggestions …
Is there an online running version of your post?

Michel

Hi Michel (@maajdl),

looks actually fine for me.
Seems only the input field is missing.
Did you try to comment //setFrameHeight(200); out?

Best regards
Chris

2 Likes

Yes, thanks Chris .
That was the problem.
Michel

1 Like

Thanks, @chris_klose !

BTW, I just realized the Markdown interpreter ate the underscores from __init__.py. Fixed it now

2 Likes

Right.
Did the same.
Thanks
Michel