CanvasLowerer
CanvasLowerer is the low-level helper that powers the higher-level canvas(...) function in the authoring widgets crate.
Most app authors should not start here. If your goal is ordinary product UI, compose normal widgets first. Reach for CanvasLowerer only when you are building a reusable library helper and need direct control over the lowering closure that emits intermediate representation ids.
This type exists because some custom drawing paths are easier to express as direct lowering code than as ordinary widget composition. It is an advanced escape hatch, not the default way to build app user interface and not a replacement for impl From<Component> for Widget.
Example
The example below shows the shape of the type, but in most app code you would wrap this in your own helper rather than constructing it at call sites.
use std::sync::Arc;
use fission::prelude::*;
let sparkline: Widget = CustomWidget {
debug_tag: "Sparkline".into(),
lowerer: Some(Arc::new(CanvasLowerer {
width: Some(120.0),
height: Some(32.0),
painter: Arc::new(|cx| {
// Emit paint or layout nodes and return their ids.
Vec::new()
}),
})),
render_object: None,
}.into();
Field table
| | | |
|---|
| | Fixed width for the root box. | None leaves width to parent constraints. |
| | Fixed height for the root box. | None leaves height to parent constraints. |
| Arc<dyn Fn(&mut InternalLoweringCx) -> Vec<WidgetId> + Send + Sync> | Closure that emits child IR ids directly into the lowering context. | Required. This is the advanced part of the public contract. |
Behavior and escape-hatch guidance
CanvasLowerer lowers its emitted node ids into a structural group and wraps that group in a fixed-size box. It does not add semantics, input handling, or a custom render object on its own.
That means it is best for lightweight custom drawing helpers. If the surface also needs pointer handling, text input, custom hit testing, or runtime painting, you are usually in CustomWidget territory rather than plain CanvasLowerer territory.
Another important limit is maintainability. Direct lowering code is powerful, but it is easier to misuse than ordinary widgets. If a layout can be expressed with Container, Row, Column, or Composite, prefer those first.
Production checklist
For CanvasLowerer, review the fields that change behavior before treating the widget as finished: width, height, painter. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
If this widget appears inside an interactive flow, keep the surrounding action binding in the parent component and test that the flow still has one clear reducer path.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Prefer parent layout and design-system sizing first; use explicit size or spacing fields when the product layout requires that constraint on this widget specifically.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same CanvasLowerer setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
canvas(...), CustomWidget, and Composite.