YouBothAgent▾
You — Business rules and flows you own. Read these yourself.
Both — Know the idea; your agent follows the details.
Agent — Conventions and references your agent follows. Look up as needed.
Workspace▾
App & Library▾
Domain▾
Scalar▾
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
Price.Template
Parent
Product.Template
Shell
Load.Edit
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
TermDescription
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.tsxIn 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
GeneralNamed 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.tsxedits the value and<Scalar>.Unit.tsxdisplays it. A scalar folder has no Zone, View or Util. - Name the file after its folder. The
price/folder holdsPrice.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
valuecomes in,onChangegoes out. The parent owns the value, so the Template keeps nouseState.patchhands back a wholePrice. It copiesvalue, applies the one changed field and passes the result toonChange.- Labels come from the scalar's dictionary.
l("price.amount")reads theprice.dictionary.tsin the same folder. - The inner fields are not agent tools.
patchis a closure, so they emit nodata-akan-action. An agent sets the price through the parent'sfillProductForminstead.


Copy the scalar with
new cnst.Price().set(value), never {...value}. A model instance keeps its Date fields behind prototype accessors, so a spread and Object.keys both miss them and the copy silently loses every date.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.priceis the value. The price lives in the parent's draft as one field.st.do.setPriceOnProductreceives the whole newPrice. The store generates a setter for every field, scalar fields included.Pricecomes from@apps/koyo/client, the same import that gives youstandusePage.


Pass the generated setter by reference. An inline arrow such as
onChange={(v) => st.do.setNameOnProduct(v)} runs the same but emits no data-akan-action, so the field publishes no agent tool and no E2E selector, and lint rejects it (no-unpublished-form-setter). A wrapper that really transforms the value, as patch does above, stays legal.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:| Scalar | Control |
|---|---|
| ↳ Note | |
Price | Field.Number · Field.Text |
| Plain number and text fields, as in the example above. | |
Address | Field.Text · Field.Postcode |
Text fields, or Postcode for a Kakao address search that also returns a coordinate. | |
Coordinate | Field.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 everyDatefield. Build the copy withnew 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.setPriceOnProductover as it is.
Read next
Scalar Overview→
When a value should be a scalar, and which files its folder holds.
Scalar.Unit.tsx→
The display half: how a parent card shows the same scalar.
Model.Template.tsx→
The parent form, its generated setters and the edit shells that open it.
Form Controls→
Every
Field member and Input, with their props and defaults.