资讯动态

Gradio 自定义 HTML 组件实战:用 `gr.HTML` 构建可交互的自定义前端组件

发布时间:2026/9/10 5:11:04 来源:尧图企业网站定制
Gradio 自定义 HTML 组件实战用gr.HTML构建可交互的自定义前端组件【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio导读本文聚焦 Gradio 官方指南《Custom Components withgr.HTML》系统讲解如何借助gr.HTML组件在纯 Python 应用中注入任意 HTML/CSS/JavaScript从而把高度定制的前端交互能力星级评分、自定义文件上传、图表渲染、布局容器等接入 Gradio 的事件系统。读完本文你将掌握html_template/css_template双模板语法、js_on_load中的props/trigger/upload/watch/server编程模型、children子组件占位以及通过api_info/data_model接入 API 与 MCP、通过push_to_hub发布共享等完整技能。从一行 HTML 开始gr.HTML的核心价值是它的value就是一段 HTML 字符串Gradio 会原样渲染到页面中。最简单的用法如下import gradio as gr gr.HTML(valueh1Hello World!/h1)单行静态 HTML 只是起点。真实场景中往往需要把动态数据Python 端传入的value、后端返回的组件状态渲染进 HTML 骨架这就引出html_template模板机制。模板化{{}}与${}两种语法并存gr.HTML支持在html_template中混用两种模板语法${}内嵌 JavaScript 表达式模板字符串求值可执行任意自定义 JS 逻辑例如调用数组方法、字符串拼接{{}}Handlebars 结构化模板用于#each循环、#if条件等场景。最简单的注入示例gr.HTML( valueJohn, html_templateh1Hello, {{value}}!/h1p${value.length} letters/p, )渲染结果为h1Hello, John!/h1p4 letters/p注意value在两种语法中都可以被引用{{value}}直接输出字符串${value.length}则把它当作 JS 变量求值。再看一个渲染列表的完整示例对应仓库演示 demo/star_rating_simple/run.py 所同属的一批 HTML 演示gr.HTML( value[apple, banana, cherry], html_template h1${value.length} fruits:/h1 ul {{#each value}} li{{this}}/li {{/each}} /ul , )这里${value.length}负责输出数组长度{{#each value}}负责遍历数组{{this}}取出当前项。二者配合即能完成“动态数据 结构化布局”的组合。默认样式、apply_default_css与css_template默认情况下gr.HTML内容会套用一部分与 Gradio 主题一致的默认 CSS。若想完全脱离主题、裸渲染自己的内容可设置apply_default_cssFalse。同时你可以通过css_template传入组件专属的 CSS。在 gradio/components/html.py 的构造函数文档中可以看到css_template同样按 JS 模板字符串与 Handlebars 语法求值且CSS 会被自动限定scoped到该组件作用域——不带选择器前缀的规则直接作用于组件根元素。这一机制让多实例组件之间互不串扰。下面的星形评分示例同时用到了css_templateimport gradio as gr with gr.Blocks() as demo: three_star_rating gr.HTML( h2Star Rating:/h2 img srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg img srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg img srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg img classfaded srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg img classfaded srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg , css_template img { height: 50px; display: inline-block; } .faded { filter: grayscale(100%); opacity: 0.3; } ) if __name__ __main__: demo.launch()完整可运行版本见 demo/star_rating_simple/run.py。响应式更新模板随value自动重渲染gr.HTML并非静态标签——当组件作为某个 Python 事件监听器的输出时模板会自动用新value重渲染。将上文的静态星星改为由value动态驱动的版本import gradio as gr with gr.Blocks() as demo: star_rating gr.HTML( value3, html_template h2Star Rating:/h2 ${Array.from({length: 5}, (_, i) img class${i value ? : faded} srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg).join()}, css_template img { height: 50px; display: inline-block; } .faded { filter: grayscale(100%); opacity: 0.3; } ) rating_slider gr.Slider(0, 5, 3, step1, labelSelect Rating) rating_slider.change(fnlambda x: x, inputsrating_slider, outputsstar_rating) if __name__ __main__: demo.launch()拖动滑块时value变化会触发模板中${...}表达式的重新求值星星的亮/灰状态随之刷新。完整演示位于 demo/star_rating_templates/run.py。传递任意 propskwargs驱动模板与样式除value外模板里可以引用任意自定义属性——只需把模板中出现的占位名作为关键字参数传给gr.HTML它们即会进入props。下例为评分组件增加size星星像素尺寸与max_stars星星总数并且html_template与css_template都能访问这些额外 propsimport gradio as gr with gr.Blocks() as demo: star_rating gr.HTML( 7, size40, max_stars10, html_template h2Star Rating:/h2 ${Array.from({length: max_stars}, (_, i) img class${i value ? : faded} srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg).join()}, css_template img { height: ${size}px; display: inline-block; } .faded { filter: grayscale(100%); opacity: 0.3; } ) rating_slider gr.Slider(0, 10, step1, labelSelect Rating) rating_slider.change(fnlambda x: x, inputsrating_slider, outputsstar_rating) size_slider gr.Slider(20, 100, 40, step1, labelSelect Size) size_slider.change(fnlambda x: gr.HTML(sizex), inputssize_slider, outputsstar_rating) if __name__ __main__: demo.launch()更关键的是这些 props 也可以通过 Gradio 事件监听器被更新。例如size_slider.change返回gr.HTML(sizex)组件便会带着新size重渲染模板与 CSS。演示文件见 demo/star_rating_props/run.py。用js_on_load触发事件构建自定义输入组件gr.HTML不仅能展示内容还能当输入组件用。机制是给组件提供js_on_load——一段在组件加载时执行的 JavaScript。这段代码的作用域内有两个关键对象element组件自身的 DOM 根元素可用element.querySelector(...)取子元素props组件全部 props 的引用对象包括valuetrigger(事件名, 数据)触发可被 Python 侧监听的事件函数upload(file)把 JSFile对象上传到 Gradio 服务器返回含path服务端路径与url公网访问地址的对象函数watch(...)监听 prop 变化回调见后文server在声明了server_functions时出现的异步方法集合见后文。下面为星形评分组件加交互点击星星通过props.value index 1更新分值模板随即重渲染点击提交按钮触发submit事件import gradio as gr with gr.Blocks() as demo: star_rating gr.HTML( value3, html_template h2Star Rating:/h2 ${Array.from({length: 5}, (_, i) img class${i value ? : faded} srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg).join()} button idsubmit-btnSubmit Rating/button , css_template img { height: 50px; display: inline-block; cursor: pointer; } .faded { filter: grayscale(100%); opacity: 0.3; } , js_on_load const imgs element.querySelectorAll(img); imgs.forEach((img, index) { img.addEventListener(click, () { props.value index 1; }); }); const submitBtn element.querySelector(#submit-btn); submitBtn.addEventListener(click, () { trigger(submit); }); ) rating_output gr.Textbox(labelSubmitted Rating) star_rating.submit(lambda x: x, inputsstar_rating, outputsrating_output) if __name__ __main__: demo.launch()在 Python 端star_rating.submit(...)就是普通的事件监听调用gr.HTML在 gradio/components/html.py 中声明EVENTS all_events因此.submit、.click等各类事件均可直接挂接。对应演示见 demo/star_rating_events/run.py。向事件传递数据gr.EventDatatrigger可携带任意数据Python 监听函数通过gr.EventData读取trigger(event_name, { key: value, count: 123 });def handle_event(evt: gr.EventData): print(evt.key) # 对应 value print(evt.count) # 对应 123 star_rating.event(fnhandle_event, inputs[], outputs[])事件的命名是自由的只要该事件名以带引号的形式出现在js_on_load字符串中例如trigger(select)就能在 Python 端写成component.select(fn, ...)。动态元素的监听技巧js_on_load只在组件首次渲染时执行一次。如果你的组件会在运行时动态创建需要绑事件的新元素应当把监听器挂到加载时即存在且不会消失的父元素上再用e.target.matches(...)判断实际点击目标element.addEventListener(click, (e) { if (e.target e.target.matches(.child-element)) { props.value e.target.dataset.value; } });内置upload把 JSFile传给 Pythonjs_on_load作用域内置的异步函数upload可直接上传浏览器File对象到 Gradio 服务器const { path, url } await upload(file);据此可用纯 HTML 构建一个文件上传小部件。完整的自定义上传演示见 demo/html_upload/run.py其核心逻辑如下import gradio as gr from pathlib import Path with gr.Blocks() as demo: file_uploader gr.HTML( html_template div input typefile idfile-input accept.txt,text/plain / button idupload-btn stylemargin-left: 8px;Upload/button /div , js_on_load const input element.querySelector(#file-input); const btn element.querySelector(#upload-btn); btn.addEventListener(click, async () { const file input.files[0]; const { path } await upload(file); props.value path; }); , elem_idfile_uploader ) view_content_btn gr.Button(View Uploaded File Content) upload_content gr.Textbox(labelUploaded File Content) view_content_btn.click(lambda path: Path(path).read_text(), file_uploader, upload_content) if __name__ __main__: demo.launch()用户选择本地文件后前端把File上传得到服务端path再写回props.value于是 Python 端click回调可以直接用该路径读文件内容。监听 prop 变化watch当gr.HTML作为 Python 事件监听器的输出时js_on_load内的watch函数可在特定 props 变化后执行回调回调内直接读取props即可拿到最新值// 监听单个 prop watch(value, () { console.log(value is now:, props.value); }); // 同时监听多个 props watch([value, color], () { console.log(value or color changed); });这在需要“Python 端更新了输出 → 前端做出附带反应”的场景如联动动画、二次渲染中很实用。通过head加载第三方脚本库head参数可向文档head注入原生 HTML典型为script/link标签用于加载外部 JS/CSS 库。head内容会在js_on_load运行前被注入并加载完毕因此js_on_load中可以立即使用该库。用 Chart.js 画柱状图示例gr.HTML( value[30, 70, 45, 90, 60], html_templatecanvas idchart/canvas, js_on_load new Chart(element.querySelector(#chart), { type: bar, data: { labels: props.value.map((_, i) Item (i 1)), datasets: [{ label: Values, data: props.value }] } }); , headscript srchttps://cdn.jsdelivr.net/npm/chart.js/script, )在 gradio/components/html.py 的参数说明中官方特别提醒head中的脚本会按src、样式按href去重多个组件需要同一库时不会被重复加载。需要留意的是浏览器不会执行通过innerHTML插入的script标签html.py 里有一处专门的告警逻辑若value/模板内容含有script会提示改用head或js_on_load。调用 Pythonserver_functions把 Python 函数列表传给server_functions后它们会成为js_on_load中server对象的异步方法。下例把os.listdir风格的list_files暴露给前端按钮调用见 demo/html_server_functions/run.pyimport os import gradio as gr def list_files(path): try: return os.listdir(path) except (FileNotFoundError, PermissionError) as e: return [fError: {e}] with gr.Blocks() as demo: gr.Markdown(# Server Functions Demo\nClick Load Files to list files in the directory.) filetree gr.HTML( valueos.path.dirname(__file__), html_template div pDirectory: strong${value}/strong/p div classtree/div button classload-btnLoad Files/button /div , js_on_load const loadBtn element.querySelector(.load-btn); const tree element.querySelector(.tree); loadBtn.addEventListener(click, async () { const files await server.list_files(props.value); tree.innerHTML ; files.forEach(file { const fileEl document.createElement(div); fileEl.textContent file; tree.appendChild(fileEl); }); }); , server_functions[list_files], ) if __name__ __main__: demo.launch()封装可复用组件类如果同一套 HTML 模板在多处复用应把gr.HTML子类化将模板与配置固化进构造函数。仓库演示 demo/star_rating_component/run.py 是一个典型实现import gradio as gr class StarRating(gr.HTML): def __init__(self, label, value0, **kwargs): html_template h2${label} rating:/h2 ${Array.from({length: 5}, (_, i) img class${i value ? : faded} srchttps://upload.wikimedia.org/wikipedia/commons/d/df/Award-star-gold-3d.svg).join()} css_template img { height: 50px; display: inline-block; cursor: pointer; } .faded { filter: grayscale(100%); opacity: 0.3; } js_on_load const imgs element.querySelectorAll(img); imgs.forEach((img, index) { img.addEventListener(click, () { props.value index 1; }); }); super().__init__(valuevalue, labellabel, html_templatehtml_template, css_templatecss_template, js_on_loadjs_on_load, **kwargs) def api_info(self): return {type: integer, minimum: 0, maximum: 5}随后在 Blocks 里如同普通组件一样实例化、参与数据流with gr.Blocks() as demo: gr.Markdown(# Restaurant Review) food_rating StarRating(labelFood, value3) service_rating StarRating(labelService, value3) ambience_rating StarRating(labelAmbience, value3) average_btn gr.Button(Calculate Average Rating) rating_output StarRating(labelAverage, value3) def calculate_average(food, service, ambience): return round((food service ambience) / 3) average_btn.click( fncalculate_average, inputs[food_rating, service_rating, ambience_rating], outputsrating_output ) if __name__ __main__: demo.launch()注意Gradio 要求所有组件构造器接受某些内部参数如render。你无需处理这些参数但必须在其上接受并转发给父类。最省事的写法就是在__init__中加上**kwargs并原样传给super().__init__()否则组件行为可能异常——这正是上文StarRating.__init__(self, label, value0, **kwargs)的用意。仓库内 gradio/components/custom_html_components 目录收录了audio_gallery.py、colored_checkbox_group.py等子类化示例可作为参考。用children把其他 Gradio 组件嵌入 HTMLgr.HTML是BlockContext子类见 gradio/components/html.py因此可作with容器使用。在html_template顶层放置children占位符with块内声明的 Gradio 组件便会渲染到该位置——用这种方式能用 HTML/CSS 自由编排自定义布局。约束children必须位于模板顶层不能被任何 HTML 标签嵌套若要给子组件容器加样式或交互需像普通 CSS 一样直接定位包裹子组件的父元素。演示见 demo/html_children/run.pyimport gradio as gr with gr.Blocks() as demo: with gr.HTML(html_template button classmaximize#x26F6;/button h2${form_name}/h2 children button classsubmitSubmit/button , css_template border: 2px solid gray; border-radius: 12px; padding: 20px; .maximize { position: absolute; top: 10px; right: 10px; background: none; border: none; z-index: 1000; } , js_on_load element.querySelector(.submit).addEventListener(click, () { trigger(submit); }); element.querySelector(.maximize).addEventListener(click, () { element.requestFullscreen(); }); , form_nameCustom Form) as form: name gr.Textbox(labelName) email gr.Textbox(labelEmail) output gr.Textbox(labelOutput) form.submit(lambda name, email: fName: {name}, Email: {email}, inputs[name, email], outputsoutput) demo.launch()这里的 Name / Email 两个 Textbox 会替换children占位符出现在“自定义表单卡片”内部卡片外层边框、右上角最大化按钮等样式/脚本均作用于容器的父元素。让组件接入 API 与 MCP要使自定义 HTML 组件适配 Gradio 内置的 API含 MCP即 Model Context Protocol能力必须定义其数据的序列化格式官方提供两种方式方式一定义api_info()方法返回描述数据格式的 JSON Schema 字典。上面的StarRating.api_info()返回整数区间约束即为此法def api_info(self): return {type: integer, minimum: 0, maximum: 5}方式二定义 Pydantic 数据模型适用于更复杂的数据结构。模型需继承GradioModel数据为具名字段的字典或GradioRootModel数据为字符串、列表等无需字典包装的简单类型from gradio.data_classes import GradioModel, GradioRootModel class MyComponentData(GradioModel): items: List[str] count: int class MyComponent(gr.HTML): data_model MyComponentData定义data_model后组件会自动实现 API 方法无需手写api_info()。共享组件push_to_hub对任意gr.HTML实例或子类调用push_to_hub即可把组件推送到社区画廊HTML Components Gallery供他人浏览、交互并复制 Python 代码star_rating StarRating() star_rating.push_to_hub( nameStar Rating, descriptionInteractive 5-star rating with click-to-rate, authoryour-hf-username, tags[input, rating], repo_urlhttps://github.com/your-username/your-repo, )这会向画廊的 HuggingFace 数据集仓库发起一个 Pull Request审核通过后组件即公开展示。两点使用提示push_to_hub自身也有head参数需要专门关注如果组件通过headscript src...加载了外部库请把同样的head字符串传给push_to_hub以便画廊渲染组件时也能加载这些脚本推送需要 HuggingFace写权限 token可直接传参push_to_hub(..., tokenhf_xxxxx)或提前执行huggingface-cli login使用缓存凭据。安全注意事项用gr.HTML做自定义组件本质是向应用注入原始 HTML 与 JavaScript因此必须防范注入风险不要把不可信的用户输入拼进html_template与js_on_load否则可能引发跨站脚本XSS漏洞凡是以gr.HTML组件为输入的任何 Python 事件监听器都可能收到任意值而非仅前端期望写入value的合法取值——公网应用应对用户输入做充分校验与净化。延伸阅读若需进一步了解各组件实例可查看同目录指南 07_custom-CSS-and-JS.md配合自定义前端交互组件基类与完整参数定义见 gradio/components/html.py其中的 docstring 提供了官方示例、head/server_functions/watch/upload等参数的权威说明可复用子类组件范例见 gradio/components/custom_html_components含audio_gallery.py、colored_checkbox_group.py仓库中super_html等大量演示demo/super_html/run.py 即为gr.HTML官方引用 demo可用于对照学习。【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价