Custom UI file uploader

Summary

Hello, I’m trying to make my own file uploader which UI is different from st.file_uploader. Because, when I use st.file_uploader it shows information that tells users to upload file under 200mb which my app requires file under 2mb(and want to change UI also). So, is there anyway to make custom file upload UI with function of file upload? So far, I made simple file uploader UI and through this I can choose file that i want to upload(later st.image), but it doesn’t return anything.

Thank you for your wonderful platform, because of you guys, i can make what i wanted to make for two years. Since I’m not a developer and using chat-gpt to make app i would be more happier if this can happen.

Expected behavior:

i want to return uploaded file, with using st.image.

thank you!

Steps to reproduce

Code snippet:

def custom_image_uploader_ui():
    st.write(
        """
        <style>
            .image-uploader-container {
                display: flex;
                flex-direction: column;
                align-items: center;
                background-color: #f0f0f0;
                padding: 20px;
                border-radius: 5px;
                margin-bottom: 20px;
                width: 50%;
            }
            .image-uploader-label {
                font-weight: bold;
                font-size: 16px;
                margin-bottom: 10px;
            }
            .image-uploader {
                cursor: pointer;
            }
        </style>
        """,
        unsafe_allow_html=True
    )


    with open("custom_image_uploader.html", "r", encoding="utf-8") as f:
        html_string = f.read()   

    st.markdown(html_string, unsafe_allow_html=True)

    if "uploaded_image_base64" in st.session_state:
        img_data = base64.b64decode(st.session_state.uploaded_image_base64.split(",")[1])
        uploaded_file = BytesIO(img_data)
        return uploaded_file
    else:
        return None

uploaded_image = custom_image_uploader_ui()

if uploaded_image is not None:
    img = Image.open(uploaded_image)
    st.image(img)


custom_image_upload.html is like next:
<!DOCTYPE html>
<html>
<head>
  <style>
    .image-uploader-container {
      ...
    }
  </style>
</head>
<body>
  <div class="image-uploader-container">
    <div class="image-uploader-label">이미지 업로드</div>
    <input type="file" accept="image/*" id="image-uploader" class="image-uploader" name="image-uploader">
  </div>
  <script>
    document.getElementById("image-uploader").addEventListener("change", (event) => {
      const file = event.target.files[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          let message = {
            type: "setSessionState",
            key: "uploaded_image_base64",
            value: e.target.result,
          };
          window.parent.postMessage(message, "*");
          
          // Trigger Streamlit rerun
          message = {type: "rerunScript"};
          window.parent.postMessage(message, "*");
        };
        reader.readAsDataURL(file);
      }
    });
  </script>
</body>
</html>

(in the image, 파일 선택 means “choose a file”)
i found code that displays image through custom UI and it works. I want to use the displayed image for later(in my app, use it for another page), i can’t find how to do this.

code for custom UI of fie uploader(sorry for all code is not in code box, if someone tells me how to do it, i will) :

//
import streamlit as st
import streamlit.components.v1 as components

js = components.html(f"“”

#image-uploader-label {{
font-size: 40px;
}}
#image-uploader {{
background-color: red;
color: white;
padding: 10px;
border-radius: 5px;
border: none;
font-size: 16px;
}}


{name}




var imgElement = null;

    // Define the handleFileUpload function to handle the file selection event
    function handleFileUpload(event) {{
        var file = event.target.files[0];
        var fileReader = new FileReader();
        fileReader.onload = function(event) {{
            imgData = event.target.result;
            // Use the imgData to display the image
            if (imgElement === null) {{
                imgElement = document.createElement("img");
                imgElement.className = "uploaded-image";
                var containerElement = document.querySelector(".image-uploader-container");
                containerElement.appendChild(imgElement);
            }}
            imgElement.src = imgData;
        }};
        fileReader.readAsDataURL(file);
    }}
</script>

“”", height=700)

Hi @JAY_jay,

Thanks for sharing this question!

To build a file uploader widget, you’d need to build a bidirectional component. We have a great guide on building components and even have templates available here.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.