Solara reactive web app best practices — components, layout, routing, testing, and common pitfalls. Load related skills for hooks, threading, and caching details.
Components are decorated functions, not classes. UI is built by calling Solara widgets inside context managers:
import solara
@solara.component
def UserCard(name: str, email: str):
with solara.Card(f"User: {name}"):
solara.Text(email)
solara.Button("Edit", on_click=lambda: edit_user(name))
Three levels of state — see the solara-hooks skill for full details:
solara.reactive(value) — global/shared state at module level.solara.use_state(initial) — component-local state.solara.use_reactive(value) — bridges reactive variables and plain values for flexible component APIs.Rules of hooks: always call at the top level, same order every render, only inside @solara.component. See the solara-hooks skill for the complete reference.
@solara.component
def Page():
with solara.AppLayout():
with solara.Sidebar():
NavigationMenu()
with solara.Column():
MainContent()
Key containers: Column, Row, Card, AppLayout, Sidebar, Columns, ColumnsResponsive.
Directory-based routing — each .py file in pages/ becomes a route:
my-app/
├── sol.py # Entry point (or __main__.py)
└── pages/
├── home.py # Route: /
├── settings.py # Route: /settings
└── about.py # Route: /about
Each page module must define a Page component.
Prefer headless tests (faster, more reliable than browser tests):
import solara
import ipyvuetify as v
def test_click_counter():
clicks = solara.reactive(0)
@solara.component
def ClickButton():
solara.Button(f"Clicked: {clicks.value}",
on_click=lambda: clicks.set(clicks.value + 1))
box, rc = solara.render(ClickButton(), handle_error=False)
button = box.children[0]
assert isinstance(button, v.Btn)
assert button.children[0] == "Clicked: 0"
button.click()
assert clicks.value == 1
solara.render() and inspect the widget tree.rc.find(v.Btn) to locate widgets in complex trees.ipyvuetify attribute conventions — Python reserved words get an underscore suffix, kebab-case becomes snake_case:
style -> style_, class -> class_ (e.g. style_="width: 100px", class_="ma-2")append-icon -> append_icon, v-model -> v_modelTrue (e.g. clearable=True)Inject CSS with solara.Style:
@solara.component
def Page():
solara.Style("body { --sidebar-width: 300px; }")
Place .css files in an assets/ directory at your app root for automatic inclusion.
Custom components — use reacton.ipyvuetify as rv for type-safe ipyvuetify wrappers:
import reacton.ipyvuetify as rv
@solara.component
def CustomChip(label: str, on_close: Callable):
chip = rv.Chip(children=[label], close_=True)
rv.use_event(chip, "click:close", lambda *_: on_close())
return chip
| Avoid | Do Instead |
|---|---|
| solara.reactive() inside a component | Use solara.use_state() for local state |
| Mutating reactive variables during render | Mutate only in callbacks or use_effect |
| Hooks inside conditionals or loops | Always call hooks at the top level |
| Monolithic components (>50 lines) | Break into smaller, composable components |
| Browser tests for pure logic | Use headless solara.render() tests |
| style="..." or class="..." on ipyvuetify | Use style_="..." and class_="..." |
Load these for deeper guidance on specific topics:
use_state, use_reactive, use_effect, use_memo, use_previous, etc.) with decision guide and rules.use_task, use_thread, @task decorator).use_memo vs @solara.memoize vs solara.cache.storage).Load this skill when building or modifying Solara applications. Load the related skills when working with hooks, threading, or caching specifically.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer