Build an anywidget component with vanilla JavaScript and proper styling.
Instructions
When creating an anywidget:
Use vanilla JavaScript in _esm:
Define a render function that takes { model, el } as parameters
Use model.get() to read trait values
Use model.set() and model.save_changes() to update traits
Listen to changes with model.on("change:traitname", callback)
Export default with export default { render }; at the bottom
Include _css styling:
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 widget.value which returns a dictionary
Keep examples minimal:
Show basic usage only
Don't combine with other marimo UI elements unless explicitly requested
Example Structure
import anywidget
import traitlets
class MyWidget(anywidget.AnyWidget):
_esm = """
function render({ model, el }) {
// Your vanilla JavaScript here
let value = model.get("trait_name");
// Create elements
let container = document.createElement("div");
// Listen to changes
model.on("change:trait_name", () => {
// Update UI
});
el.appendChild(container);
}
export default { render };
"""
_css = """
/* Light mode styles */
.container {
/* styles */
}
/* Dark mode styles */
@media (prefers-color-scheme: dark) {
.container {
/* dark mode styles */
}
}
"""
trait_name = traitlets.Unicode("default").tag(sync=True)
# Wrap with marimo
widget = mo.ui.anywidget(MyWidget())
widget
Accessing Values
# In another cell
widget.value["trait_name"]
1---2name: anywidget-dev3description: anywidget Development4---5# anywidget Development67Build an anywidget component with vanilla JavaScript and proper styling.89## Instructions1011When creating an anywidget:12131. **Use vanilla JavaScript in `_esm`**:14 - Define a `render` function that takes `{ model, el }` as parameters15 - Use `model.get()` to read trait values16 - Use `model.set()` and `model.save_changes()` to update traits17 - Listen to changes with `model.on("change:traitname", callback)`18 - Export default with `export default { render };` at the bottom19202. **Include `_css` styling**:21 - Keep CSS minimal unless explicitly asked for more22 - Make it look bespoke in both light and dark mode23 - Use CSS media query for dark mode: `@media (prefers-color-scheme: dark) { ... }`24253. **Wrap the widget for display**:26 - Always wrap with marimo: `widget = mo.ui.anywidget(OriginalAnywidget())`27 - Access values via `widget.value` which returns a dictionary28294. **Keep examples minimal**:30 - Show basic usage only31 - Don't combine with other marimo UI elements unless explicitly requested3233## Example Structure3435```python36import anywidget37import traitlets3839class MyWidget(anywidget.AnyWidget):40 _esm = """41 function render({ model, el }) {42 // Your vanilla JavaScript here43 let value = model.get("trait_name");4445 // Create elements46 let container = document.createElement("div");4748 // Listen to changes49 model.on("change:trait_name", () => {50 // Update UI51 });5253 el.appendChild(container);54 }55 export default { render };56 """5758 _css = """59 /* Light mode styles */60 .container {61 /* styles */62 }6364 /* Dark mode styles */65 @media (prefers-color-scheme: dark) {66 .container {67 /* dark mode styles */68 }69 }70 """7172 trait_name = traitlets.Unicode("default").tag(sync=True)7374# Wrap with marimo75widget = mo.ui.anywidget(MyWidget())76widget77```7879## Accessing Values8081```python82# In another cell83widget.value["trait_name"]84```
Run npx skillmds@latest add koaning/anywidget-dev in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
anywidget Development It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
koaning (@koaning) published this skill. Their other Agent Skills are listed on their SkillMD profile.