anywidget-generator
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWhen writing an anywidget use vanilla javascript in and do not forget about . The css should look bespoke in light mode and dark mode. Keep the css small unless explicitly asked to go the extra mile. When you display the widget it must be wrapped via . You can also point and to external files if needed using pathlib. This makes sense if the widget does a lot of elaborate JavaScript or CSS.
<example title="Example of simple anywidget implementation">
import anywidget
import traitlets
_esm_csswidget = mo.ui.anywidget(OriginalAnywidget())_esm_cssclass CounterWidget(anywidget.AnyWidget):
_esm = """
// Define the main render function
function render({ model, el }) {
let count = () => model.get("number");
let btn = document.createElement("b8utton");
btn.innerHTML = ;
btn.addEventListener("click", () => {
model.set("number", count() + 1);
model.save_changes();
});
model.on("change:number", () => {
btn.innerHTML = ;
});
el.appendChild(btn);
}
// Important! We must export at the bottom here!
export default { render };
"""
_css = """button{
font-size: 14px;
}"""
number = traitlets.Int(0).tag(sync=True)
count is ${count()}count is ${count()}widget = mo.ui.anywidget(CounterWidget())
widget
在编写anywidget时,请在中使用原生JavaScript(vanilla javascript),不要忘记。CSS需要在浅色模式和深色模式下都有独特的外观,除非明确要求进一步扩展,否则请保持CSS代码精简。在展示组件时,必须通过进行包装。如果需要,你也可以使用pathlib将和指向外部文件,当组件需要大量复杂的JavaScript或CSS代码时,这种方式会很实用。
<example title="简单anywidget实现示例">
import anywidget
import traitlets
_esm_csswidget = mo.ui.anywidget(OriginalAnywidget())_esm_cssclass CounterWidget(anywidget.AnyWidget):
_esm = """
// 定义主渲染函数
function render({ model, el }) {
let count = () => model.get("number");
let btn = document.createElement("button");
btn.innerHTML = ;
btn.addEventListener("click", () => {
model.set("number", count() + 1);
model.save_changes();
});
model.on("change:number", () => {
btn.innerHTML = ;
});
el.appendChild(btn);
}
// 重要!必须在底部导出!
export default { render };
"""
_css = """button{
font-size: 14px;
}"""
number = traitlets.Int(0).tag(sync=True)
count is ${count()}count is ${count()}widget = mo.ui.anywidget(CounterWidget())
widget
Grabbing the widget from another cell, .value
is a dictionary.
.value从其他单元格获取组件,.value
是一个字典。
.valueprint(widget.value["number"])
</example>
The above is a minimal example that could work for a simple counter widget. In general the widget can become much larger because of all the JavaScript and CSS required. Unless the widget is dead simple, you should consider using external files for and using pathlib.
_esm_cssWhen sharing the anywidget, keep the example minimal. No need to combine it with marimo ui elements unless explicitly stated to do so.
print(widget.value["number"])
</example>
以上是一个简单计数器组件的最小示例。通常情况下,由于需要大量JavaScript和CSS代码,组件可能会变得更复杂。除非组件极其简单,否则你应该考虑使用pathlib将和指向外部文件。
_esm_css在分享anywidget时,请保持示例精简。除非明确要求,否则不要将其与marimo UI元素结合使用。
Best Practices
最佳实践
Unless specifically told otherwise, assume the following:
-
Use vanilla JavaScript in:
_esm- Define a function that takes
renderas parameters{ model, el } - Use to read trait values
model.get() - Use and
model.set()to update traitsmodel.save_changes() - Listen to changes with
model.on("change:traitname", callback) - Export default with at the bottom
export default { render }; - All widgets inherit from , so
anywidget.AnyWidgetremains the standard way to react to state changes.widget.observe(handler) - Python constructors tend to validate bounds, lengths, or choice counts; let the
raised guide you instead of duplicating the logic.
ValueError/TraitError
- Define a
-
Includestyling:
_css- Keep CSS minimal unless explicitly asked for more
- Make it look bespoke in both light and dark mode
- Use CSS media query for dark mode:
@media (prefers-color-scheme: dark) { ... }
-
Wrap the widget for display:
- Always wrap with marimo:
widget = mo.ui.anywidget(OriginalAnywidget()) - Access values via which returns a dictionary
widget.value
- Always wrap with marimo:
-
Keep examples minimal:
- Add a marimo notebook that highlights the core utility
- Show basic usage only
- Don't combine with other marimo UI elements unless explicitly requested
Dumber is better. Prefer obvious, direct code over clever abstractions—someone
new to the project should be able to read the code top-to-bottom and grok it
without needing to look up framework magic or trace through indirection.
除非另有明确说明,请遵循以下规则:
-
在中使用原生JavaScript:
_esm- 定义一个接收作为参数的
{ model, el }函数render - 使用读取trait值
model.get() - 使用和
model.set()更新traitmodel.save_changes() - 使用监听变化
model.on("change:traitname", callback) - 在底部通过导出默认对象
export default { render }; - 所有组件都继承自,因此
anywidget.AnyWidget仍然是响应状态变化的标准方式。widget.observe(handler) - Python构造函数通常会验证边界、长度或选项数量;请直接使用抛出的作为指导,不要重复实现逻辑。
ValueError/TraitError
- 定义一个接收
-
包含样式:
_css- 除非明确要求扩展,否则保持CSS精简
- 确保在浅色和深色模式下都有独特的外观
- 使用CSS媒体查询实现深色模式:
@media (prefers-color-scheme: dark) { ... }
-
包装组件以进行展示:
- 始终使用marimo进行包装:
widget = mo.ui.anywidget(OriginalAnywidget()) - 通过访问值,它会返回一个字典
widget.value
- 始终使用marimo进行包装:
-
保持示例精简:
- 添加一个marimo笔记本以突出核心功能
- 仅展示基础用法
- 除非明确要求,否则不要与其他marimo UI元素结合使用
越简单越好。优先选择直观、直接的代码,而非巧妙的抽象——项目的新手应该能够从上到下阅读代码并理解其含义,而无需查阅框架的魔法特性或追踪间接调用。