The context a component renders in (spec/02 §2): its mode, instance, size, root font size, heading level, theme, the viewer's preferences, the holder's now, and the cell's resolved bindings.
The host computes it: on a page the core, elsewhere the adopter. The component never
knows which, and never reads a clock: now is the holder's. bindings is
%{slot => %{role => field | [field, ...]}}, each slot's binding as
Macaw.Component.Slot.resolve/3 resolves it, so a component reads the field bound to a
role with field/3 and never repeats the defaulting rule.
iex> {:ok, ctx} = Macaw.Component.Context.new(mode: :live, instance: "cards-1", size: {640, 400}, now: ~U[2026-10-28 12:00:00Z])
iex> {Macaw.Component.Context.heading(ctx, 0), Macaw.Component.Context.heading(ctx, 1)}
{"h2", "h3"}
iex> Macaw.Component.Context.id(ctx, "item-3")
"cards-1-item-3"
iex> {:ok, ctx} = Macaw.Component.Context.new(mode: :live, instance: "chart-1", size: {640, 400}, now: ~U[2026-10-28 12:00:00Z], bindings: %{"points" => %{"x" => "t", "y" => ["in", "out"]}})
iex> {Macaw.Component.Context.field(ctx, "points", "x"), Macaw.Component.Context.field(ctx, "points", "y"), Macaw.Component.Context.field(ctx, "points", "label")}
{"t", ["in", "out"], nil}
Summary
Functions
The field bound to role of slot: a string for a one-field role, the list of fields
for a many role, nil for a slot or role the context does not bind.
The fields, in the order of spec/02 §2's table.
The heading element depth levels below the component's top (0 for its top):
"h<level + depth>", never past "h6".
An element id unique to the instance, "<instance>-<local>", stable across renders.
local is a non-empty string of letters, digits, - and _; anything else raises
ArgumentError, a programming error in the component.
A context from a keyword list or a map: {:ok, context} or every fault at once, each
{[field], reason}, an unknown field :unknown_key and a missing required one
:required. The theme defaults to Macaw.Layers.Theme.default(). A bad binding is a
fault at its path under [:bindings]: :not_a_map, :bad_name for a slot or role
that is not a non-empty string, :not_a_field for a field that is neither a non-empty
string nor a non-empty list of them.
Types
@type t() :: %Macaw.Component.Context{ bindings: %{ required(String.t()) => %{ required(String.t()) => String.t() | [String.t(), ...] } }, heading_level: 1..6, instance: String.t(), measured: boolean(), mode: Macaw.Component.Mode.t(), now: DateTime.t(), preferences: %{zone: String.t(), units: atom(), shortcuts: map()}, root_font_size: number(), size: {number(), number()}, theme: Macaw.Layers.Theme.t() }
Functions
The field bound to role of slot: a string for a one-field role, the list of fields
for a many role, nil for a slot or role the context does not bind.
@spec fields() :: [atom(), ...]
The fields, in the order of spec/02 §2's table.
@spec heading(t(), non_neg_integer()) :: String.t()
The heading element depth levels below the component's top (0 for its top):
"h<level + depth>", never past "h6".
An element id unique to the instance, "<instance>-<local>", stable across renders.
local is a non-empty string of letters, digits, - and _; anything else raises
ArgumentError, a programming error in the component.
@spec new(keyword() | map()) :: {:ok, t()} | {:error, [Macaw.Component.fault(), ...]}
A context from a keyword list or a map: {:ok, context} or every fault at once, each
{[field], reason}, an unknown field :unknown_key and a missing required one
:required. The theme defaults to Macaw.Layers.Theme.default(). A bad binding is a
fault at its path under [:bindings]: :not_a_map, :bad_name for a slot or role
that is not a non-empty string, :not_a_field for a field that is neither a non-empty
string nor a non-empty list of them.