Scalar.Template.tsx

A scalar Template is a small form piece that edits one scalar value inside a parent model's form. Write one when several models hold the same value: Product, Order and Invoice can all reuse Price.Template.
It edits the value and nothing else. Reading the draft, saving it and submitting the form happen elsewhere:
The work
Scalar
Parent
Shell
Editing the value
Field.*
✓
One control per scalar field, labelled from the scalar's dictionary.
new cnst.Price().set(value)
✓
Builds the changed value and hands it to onChange.
Keeping and saving it
st.use.productForm()
✓
Reads the parent's draft, where the price is one field.
st.do.setPriceOnProduct
✓
Writes the whole changed price back into that draft.
load · open · submit
✓
An edit shell such as Load.Edit does this around the parent Template.
✓Done hereNot here
Words used on this page
A small value object stored inside another model, such as Price with amount and currency.
parent form
The Template of the model that holds the scalar, such as Product.Template.
<model>Form
The store's draft of the record being edited, such as productForm.
st.do.set<Field>On<Model>
The setter the store generates for each field, such as setPriceOnProduct.

File Shape

The Template sits in the scalar's own folder under lib/__scalar/, next to the constant that defines the value and the dictionary that labels it:
apps/koyo
Path
apps/<app>/lib/__scalar/<scalar>/<Scalar>.Template.tsx
In the scalar's own folder, beside its constant file.
First Line
"use client";
Always. Its fields handle input events, which only run in the browser.
Exports
General
Named arrow components, each taking value and onChange.
Used As
<Price.Template.General value={…} onChange={…} />
The parent form imports Price from @apps/<app>/client.
  • A scalar has two UI files at most. <Scalar>.Template.tsx edits the value and <Scalar>.Unit.tsx displays it. A scalar folder has no Zone, View or Util.
  • Name the file after its folder. The price/ folder holds Price.Template.tsx, with the first letter capitalized.

Scalar Template Example

A scalar Template receives value and onChange and edits only that value. It loads no data and never submits the parent form:
apps/koyo/lib/__scalar/price/Price.Template.tsx
  • value comes in, onChange goes out. The parent owns the value, so the Template keeps no useState.
  • patch hands back a whole Price. It copies value, applies the one changed field and passes the result to onChange.
  • Labels come from the scalar's dictionary. l("price.amount") reads the price.dictionary.ts in the same folder.
  • The inner fields are not agent tools. patch is a closure, so they emit no data-akan-action. An agent sets the price through the parent's fillProductForm instead.

Use From Parent Form

The parent Template stays an ordinary store-driven form. It passes the embedded scalar to the scalar Template and stores what comes back with the generated setter:
apps/koyo/lib/product/Product.Template.tsx
  • productForm.price is the value. The price lives in the parent's draft as one field.
  • st.do.setPriceOnProduct receives the whole new Price. The store generates a setter for every field, scalar fields included.
  • Price comes from @apps/koyo/client, the same import that gives you st and usePage.

Field Or Custom UI

Give every scalar field a Field.* control, never a bare <input>. A Field brings the label, the validation and, when handed a store setter, the data-akan-action attribute. Pick the control by the value's shape:
ScalarControl
↳ Note
PriceField.Number · Field.Text
Plain number and text fields, as in the example above.
AddressField.Text · Field.Postcode
Text fields, or Postcode for a Kakao address search that also returns a coordinate.
CoordinateField.Coordinate
A map picker from @libs/shared/ui that sets the point where you click.
Anything else<YourComponent>
Your own component taking value and onChange, built on Input from akanjs/ui if needed.
When no Field covers the interaction, build an app component that takes value and onChange the same way, so the scalar Template can use it like a Field.
Common mistakes
  • Copying with a spread. {...value} drops every Date field. Build the copy with new cnst.Price().set(value).
  • Keeping the value in useState. The parent's draft already holds it, and the Template only forwards changes.
  • Loading or saving inside the scalar Template. Server calls go in a store action, and the edit shell around the parent submits the form.
  • Wrapping the parent's setter in an arrow. Hand st.do.setPriceOnProduct over as it is.
Read next

Released under the MIT License

Connect your AI to these docs

MCPhttps://akanjs.com/mcp
Copyright © 2026 Akan.js All rights reserved.System managed bybassman