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/

5 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