Streamlitでクリップボードにコピーボタンを実装するコードをメモしておきます。
コード
streamlit.components.v1.html
を利用したHTMLとJavaScriptの組み合わせで実装します。
この方法では、ボタンをクリックすると特定のテキストをクリップボードにコピーするHTMLフォームをStreamlitアプリに埋め込みます。
import streamlit as st
from streamlit.components.v1 import html
# コピーするテキスト
text_to_copy = "Hello, World!"
# HTMLとJavaScriptを使用してクリップボードにコピーする機能を実装
copy_button_html = f"""
<button onclick='navigator.clipboard.writeText("{text_to_copy}")'>Copy to clipboard</button>
"""
# カラム作成
col1, col2 = st.columns(2)
with col1:
# 最初のカラムにテキストを表示
st.write("ここに表示するテキスト: Hello, World!")
with col2:
# StreamlitにHTMLコンポーネントを追加
html(copy_button_html, height=50)
HTMLの<button>
要素を使用してボタンを作成し、onclick
イベントでJavaScriptのnavigator.clipboard.writeText()
メソッドを呼び出しています。
html(copy_button_html, height=50)
のheightのデフォルト値が150のため、heightを指定しないと広めの空白が入っているように見えました。
このメソッドにコピーしたいテキストを渡すことで、ユーザーのクリップボードにそのテキストをコピーします。
JavaScriptエラー対応
サーバーで上記アプリを実行したたときに、クリップボードにコピーできない事象が発生しました。
調べると以下のJavaScriptのエラーが発生していました。
Uncaught TypeError: Cannot read properties of undefined (reading 'writeText')
at HTMLButtonElement.<anonymous> (about:srcdoc:46:33)
エラーの原因は、https接続ではなくhttp接続していることでした。
navigator.clipboard.writeText が使用できないようです。
http接続で機能させたい場合は、以下のコードで実現できました。
copy_button_html = f"""
<textarea id="hiddenTextArea" style="opacity: 0; position: absolute; z-index: -1;">{text_to_copy}</textarea>
<button onclick="copyText()">Copy to clipboard</button>
<script>
function copyText() {{
// テキストエリアを選択
var copyTextArea = document.getElementById("hiddenTextArea");
copyTextArea.focus();
copyTextArea.select();
try {{
// テキストをクリップボードにコピー
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
}} catch (err) {{
console.log('Oops, unable to copy', err);
}}
}}
</script>
"""