Custom component to display clickable images

Hi! I didn’t find a way to do this with existing components so I created a simple component to display images and receive the index of the last image that was clicked on.

screenshot

A more advanced example can be seen live here.

Installation

pip install st-clickable-images

Quickstart

import streamlit as st
from st_clickable_images import clickable_images

clicked = clickable_images(
    [
        "https://images.unsplash.com/photo-1565130838609-c3a86655db61?w=700",
        "https://images.unsplash.com/photo-1565372195458-9de0b320ef04?w=700",
        "https://images.unsplash.com/photo-1582550945154-66ea8fff25e1?w=700",
        "https://images.unsplash.com/photo-1591797442444-039f23ddcc14?w=700",
        "https://images.unsplash.com/photo-1518727818782-ed5341dbd476?w=700",
    ],
    titles=[f"Image #{str(i)}" for i in range(5)],
    div_style={"display": "flex", "justify-content": "center", "flex-wrap": "wrap"},
    img_style={"margin": "5px", "height": "200px"},
)

st.markdown(f"Image #{clicked} clicked" if clicked > -1 else "No image clicked")

Usage

clickable_images(paths,titles=[], div_style={}, img_style={}, key=None)

Displays one or several images and returns the index of the last image clicked on (or -1 before any click)

Parameters

  • paths (list): the list of URLS of the images
  • titles (list): the (optional) titles of the images
  • div_style (dict): a dictionary with the CSS property/value pairs for the div container
  • img_style (dict): a dictionary with the CSS property/value pairs for the images
  • key (str or None): an optional key that uniquely identifies this component. If this is None, and the component’s arguments are changed, the component will be re-mounted in the Streamlit frontend and lose its current state
12 Likes

Awesome job @vivien! I know a lot of people have asked for this sort of functionality!

If you haven’t already, please add this to the Streamlit Components - Community Tracker so that others will be able to discover this easier :slight_smile:

Best,
Randy

2 Likes

Done! Thanks Randy

1 Like

Hi @vivien I tried your component, but it doesn’t load the images for me. I just get the “No Image Clicked” text, but clickable_images() function isn’t doing anything for me. Perhaps a package versioning issue? Can you tell if there are any minimum package requirements?

Upon further debugging, I found that paths argument is a list of urls and can’t be a list of local paths of the images currently. :+1:

Hi @therochvoices. You can provide URLs but, if your images are local files, you can also open these files, encode the images in base64, and provide “data:image/jpeg;base64,[XXX]” as paths (where [XXX] is replaced by the base64-encoded images)

1 Like

Hello @vivien

This is a very cool component! Much needed!
Is there a way currently to show the title of the image above the image as well? (Currently the title shows while hovering the mouse over the image?). Thank you!

Hi @MLbyML. Thanks. I’m afraid this isn’t possible with the component as it is now (but it shouldn’t be too complicated to do it if you want to give it a try: the javascript code to display and style the images is pretty short).

1 Like

@vivien thanks so much for sharing this, a fabulous widget which came in very handy for me today - using it to select an image when then calls an Azure image analysis service to return a description plus lists of categories, tags, landmarks, people, and brands. Love it!

1 Like

@LostGoatOnHill Thanks for the feedback. It sounds like a cool app!

@vivien you helped make this possible :slight_smile:

FYI, I created another component which is a generalization of this one: st-click-detector. It works not only on images but also on all HTML links.

Hi vivien, good day can you pls provide an exact example of this, where the image file is locally found. I am having trouble doing it. Thanks.

Hi @data.science. Here is an example:

import base64
import streamlit as st
from st_clickable_images import clickable_images

images = []
for file in ["image1.jpeg", "image2.jpeg"]:
    with open(file, "rb") as image:
        encoded = base64.b64encode(image.read()).decode()
        images.append(f"data:image/jpeg;base64,{encoded}")

clicked = clickable_images(
    images,
    titles=[f"Image #{str(i)}" for i in range(2)],
    div_style={"display": "flex", "justify-content": "center", "flex-wrap": "wrap"},
    img_style={"margin": "5px", "height": "200px"},
)

st.markdown(f"Image #{clicked} clicked" if clicked > -1 else "No image clicked")
1 Like