New Component: Streamlit JS Eval

SJE is a custom Streamlit component, built to evaluate arbitrary Javascript expressions and return the result. It can become useful in doing certain functionalities which are simple things to do in JavaScript using the Web API, but unavailable or difficult to do in Streamlit. Examples include cookie management, writing to clipboard, getting device width (e.g. to check if we are on a mobile device), getting browser language, sharing something through Android’s share feature, knowing user agent, checking the battery and network status etc.

Here is an example

st.write(f"Screen width is {streamlit_js_eval(js_expressions='screen.width', key = 'SCR')}")

I will gradually add a more popular Web API to SJE in the form of Python functions so that the user does not have to see any JavaScript. Currently, we have Python wrapper for things like accessing cookies, the clipboard, and geolocation API. Here is an example of asking user’s location


# Returns user's location after asking for permission when the user clicks the generated link with the given text

location = get_geolocation()

Hope this very basic components helps other people and also make Streamlit even ore accessible, particularly with the recent emergence of Stlite, the great work of @whitphx to enable fully client-side Streamlit.

PyPI: streamlit-js-eval · PyPI
GitHub: GitHub - aghasemi/streamlit_js_eval: A custom Streamlit component to evaluate arbitrary Javascript expressions
Demo: https://aghasemi-streamlit-js-eval-example-yleu91.streamlitapp.com/

7 Likes

Beautiful! You should definitely add this to the tracker: Streamlit Components - Community Tracker so we don’t lose track of it!

Fanilo

1 Like

Hi aghasemi,

When put in a on_click callback function, the code is not working as expected.
Below is the code:

import streamlit as st
from streamlit_js_eval import streamlit_js_eval


def disp_width():
    to_display = f"Screen width is _{streamlit_js_eval(js_expressions='screen.width', want_output = True, key = 'SCR')}_"
    print(to_display)


st.button("Display Screen Width", on_click=disp_width)

And the print result when the button “Display Screen Width” is pressed:

image

Any suggestions to solve the issue?

Dear Marc,

Sorry you ran into this. I don’t know much about the internals of callbacks in Streamlit and have not used them personally (or tested SJE against them).

As a quick fix, you can put the JS evaluation outside the callback function, like this:

import streamlit as st

from streamlit_js_eval import streamlit_js_eval


width = streamlit_js_eval(js_expressions='screen.width', want_output = True, key = 'SCR')



def disp_width():
    to_display = f"Screen width is _{width}_"
    
    print(to_display)





st.button("Display Screen Width", on_click=disp_width)

, which works on my machine. Does this fix work for you?

Hi aghasemi,

Thank you for the suggestion but I absolutelly need to get values from the localStorage many times from the code (using button callback).
If I look into the inspect console, I can see that the code tries to output the value but the value is not correctly received by the streamlit code. The error seems to be related to the reading of undefined properties.

image

Sorry, Marc. I played a bit with SJE source code and the issue is still there. It must have something to do with how callbacks work. I will create an issue in the Streamlit GitHub, but given that the components API is being rewritten, I am not sure there will be much effort on it :frowning:

Can you tag someone from the Streamlit dev team here?

Update: GitHub issue

I tried this too and found it didn’t work using the callback. I also tried with a different JavaScript API component and encountered the same issue. So, it seems that components can’t be run within a widget callback.

Thank you very much. I use streamlint_ js_ Eval solves other problems

1 Like

nice feature but since I’ve started using it my web browser is throwing lots of stcorr errors in the chrome and safari console.

This is an incredible component! I used it a few weeks ago in my app to get the latitude and longitude of my user. But now, it’s not working. I even tried the demo link multiple times, but the location feature isn’t returning any value. Please resolve this issue!

Hi. Sorry for the inconvenience. There has been no change in my code recently. Can you please confirm if it works on any other/older versions of Streamlit?

Thank you so much for the reply! I just tried it out on my phone and other laptop and it works just as perfectly as before. I believe there is an issue in my laptop. Thanks again, and sorry for the bother!

Hi @aghasemi,
thank you for your work and contribution.
I would like to ask you if I can implement an async javascript function inside the js_expressions argument and how to do it.

Thank you!

May I ask which API or library you want to use?

Hi @aghasemi,

basically we receive data from an external authenticator system and I would like to fetch the attributes which are in the session page. Something like this:

async function getUser(){
const res = await fetch('myurl/Shibboleth.sso/Session')
const data = res.json()
document.getElementById("id").textContent = id}

This is the error logged in console:
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules at onDataFromPython

Thank you very much!

Great component! This provides a great workaround to dynamically sizing Altair combo charts, since use_container_width=True does not work with Altair combo charts.

Though streamlit_js_eval works great locally, when trying to run it on the streamlit cloud I get a ModuleNotFoundError even though I have listed it in my requirements.txt.

I am running streamlit v1.26.0 and streamlit_js_eval 0.1.5 locally, which I believe are the latest version. Does anyone have an idea why streamlit cloud can’t install the package even though it’s available in pip?

Here’s the app I’m trying to run: app

Update: somehow I’ve gotten it to work after switching to a new repo with the same code

Hi. Good it worked for you. I had no idea why pip would not find it :smiley:

Hi. Can you please check the source where Promises are dealt with? Maybe you can solve it like that, even with some modifications to the package.

Source: https://github.com/aghasemi/streamlit_js_eval/blob/master/streamlit_js_eval/index.html#L107
The function get_geolocation actually uses a promise.

damn its a very nice component . it was very useful in my project

1 Like

Hi @aghasemi,

Thanks for this great component!
I’m thinking that it would be useful if I could add some more functionalities to this component, or maybe how to use it in “js_expressions” those api from the source that you have provided. This is more the state of js knowledge and creating new components, but if someone else is eager to showcase it that will be good for community to generate more functionalities.
In the Mdn web docs there is a lot of useful features. :blush:

1 Like