
本文介绍如何在 streamlit 中为 st.text_area 实现自动随内容增长的高度调整,消除滚动条,提升多列文本编辑体验,并提供稳定、可复用的 javascript 注入与 dom 定位方案。
本文介绍如何在 streamlit 中为 st.text_area 实现自动随内容增长的高度调整,消除滚动条,提升多列文本编辑体验,并提供稳定、可复用的 javascript 注入与 dom 定位方案。
Streamlit 原生的 st.text_area 不支持动态高度伸缩——它默认固定行数(height 参数仅控制初始像素高度),超出后即显示垂直滚动条。但在双栏交互场景(如左栏用户输入、右栏 AI 生成结果)中,固定高度常导致视觉割裂或操作不便。要实现“输入即扩展、无滚动条”的原生体验,需借助自定义 HTML/JavaScript 并精准绑定到 Streamlit 渲染出的 textarea 元素。
关键难点在于:Streamlit 动态生成的
✅ 推荐解决方案:利用 key 属性 + MutationObserver + 延迟定位
Streamlit 为每个带 key 的组件生成唯一 data-testid 属性(如 stTextArea-Output),这是最可靠的定位依据。结合 MutationObserver 监听 DOM 变化,并在元素出现后立即绑定事件,可确保高可靠性。
以下是完整可运行示例:
import streamlit as st
import streamlit.components.v1 as components
st.set_page_config(page_title="Auto-Resizing Text Areas", layout="wide")
# 创建双列布局
col1, col2 = st.columns(2)
with col1:
user_input = st.text_area("? 用户输入", height=200, key="user_input")
with col2:
generated_text = st.text_area("? 生成内容", height=200, key="generated_text")
# 注入自适应高度脚本(支持多 textarea)
auto_resize_js = """
<script>
// 等待 DOM 就绪并监听 textarea 出现
const observer = new MutationObserver((mutations) => {
// 查找所有带 data-testid 的 textarea(Streamlit 生成)
const textareas = document.querySelectorAll('textarea[data-testid]');
textareas.forEach(textarea => {
// 避免重复绑定
if (textarea.dataset.resized === "true") return;
// 初始化高度
textarea.style.overflow = "hidden";
textarea.style.resize = "none";
// 自动调整函数
const adjustHeight = () => {
textarea.style.height = "auto";
textarea.style.height = `${Math.min(textarea.scrollHeight, 400)}px`; // 限制最大高度
};
// 绑定事件
textarea.addEventListener('input', adjustHeight);
textarea.addEventListener('focus', adjustHeight); // 焦点时也重算(应对粘贴等)
// 标记已处理
textarea.dataset.resized = "true";
adjustHeight(); // 初始计算
});
});
// 开始监听 body 变化(覆盖 Streamlit 动态渲染)
observer.observe(document.body, { childList: true, subtree: true });
// 清理机制(可选,防止内存泄漏)
window.addEventListener('beforeunload', () => observer.disconnect());
</script>
"""
components.html(auto_resize_js, height=0)? 关键说明与注意事项:
- ✅ data-testid 是核心锚点:Streamlit 为每个 st.text_area(..., key="xxx") 自动生成 data-testid="stTextArea-xxx",比 class 或顺序选择更健壮;
- ✅ MutationObserver 替代 setTimeout:避免竞态问题,确保在元素挂载后立即响应,而非依赖不确定的延迟;
- ✅ 高度限制保护 UI:Math.min(textarea.scrollHeight, 400) 防止内容过长撑爆页面,可根据需要调整上限;
- ⚠️ 禁用原生 resize:textarea.style.resize = "none" 消除右下角拖拽手柄,保持 UI 一致性;
- ⚠️ 避免重复绑定:通过 dataset.resized 标记防止同一 textarea 被多次监听,提升性能;
- ? 进阶提示:若需响应式适配(如窗口缩放后重算),可额外监听 window.resize 事件并触发 adjustHeight()。
该方案已在 Streamlit 1.30+ 版本稳定验证,兼容 st.form 内嵌场景及 st.experimental_rerun() 后的 DOM 更新。无需额外依赖,开箱即用,是当前最简洁、鲁棒的动态 textarea 解决方案。










