OrderTicket
StableA buy or sell form to place a trade: side, quantity, order type, price, product, a review summary and one submit button.
Also known as trade form, buy sell form, order form
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Market buy
function Example() {
const [v, setV] = useState<OrderTicketValue>({ side: "buy", quantity: 10, orderType: "market", limitPrice: null, product: "intraday", stop: null, target: null });
return (
<OrderTicket symbol="RELIANCE" price={2945.5} value={v} onChange={setV} onSubmit={() => {}}
summary={[{ label: "Margin needed", value: "29,455.00", hint: "Worked out by the app." }, { label: "Charges", value: "41.20" }]} />
);
}The simple case. The app computes the summary rows and passes them in.
When to use it
Lets a person set up an order by hand, with every figure in view before they press the one button.
Made of: Symbol and last price · Side · Quantity · Order type · Price (limit and stop only) · Product · Stop and target · Summary rows · Submit button · Reason when locked
Use it for
- A manual order the person types in themselves.
- The inside of an ActionDraft when an AI drafted the order and the person edits it.
- A locked ticket that explains in words why trading is paused.
Not for
- Asking a person to approve something an agent wants to do: use ApprovalPrompt.
- Showing a finished order as a record: use Receipt.
- A single number input: use NumberField.
Do and avoid
Do
- Pass cost and risk in summary so the person sees them before pressing.
- Say why the ticket is locked with disabledReason.
- Put it inside ActionDraft for an order an AI drafted.
- Keep the button text specific, such as Buy RELIANCE.
Avoid
- Do not place the order inside onChange. Only onSubmit, from a press, may start it.
- Do not rely on the Buy and Sell words being coloured. They are not.
- Do not compute money inside this part. Pass it in.
- Do not add a second submit button.
On a phone
- The form is one column and fills the width of its container up to 430px. Only Stop and Target sit side by side.
- The submit button is full width and 48px tall on touch screens.
- Quantity and price fields use the number fields, which are 16px on touch screens so the page does not zoom when they get focus.
- Put the ticket where the on-screen keyboard will not hide the submit button, for example by letting the page scroll.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| symbolrequired | string | none | The instrument, such as RELIANCE. Used in the heading and the default button text. |
| price | number | none | Last price, shown at the top. Display only. |
| valuerequired | OrderTicketValue | none | The whole form: side, quantity, orderType, limitPrice, product, stop, target. |
| onChangerequired | (v: OrderTicketValue) => void | none | Called with the full new value on every change. |
| lotSize | number | none | Quantity moves in steps of this size and the hint reads "1 lot = 75". A quantity that is not a multiple shows an error. |
| tickSize | number | 0.05 | Step for the price, stop and target fields. |
| summary | { label: string; value: ReactNode; hint?: string }[] | none | What the order will cost or risk, worked out by the app. Shown as a definition list. |
| errors | Partial<Record<keyof OrderTicketValue, string>> | {} | One sentence per field, shown under it. |
| onSubmitrequired | () => void | none | Called when the submit button is pressed. The app decides what happens. |
| submitLabel | string | "Buy RELIANCE" style, from side and symbol | Button text. |
| submitting | boolean | none | Shows a spinner in the button and blocks another press. |
| disabled | boolean | none | Locks every field and the button. |
| disabledReason | string | none | Why it is locked, in words next to the button. Shown only when disabled. |
| className | string | none | Extra classes for the form. |
"Show code under the preview gives the code for the example on the stage."
In Figma
In Figma, one OrderTicket switches all of this from its properties panel, across 4 variants. Each property sets the React prop beside it, so design and code use the same names.
| Figma property | React | Values |
|---|---|---|
| Submitting | submitting | On or off |
| Disabled | disabled | On or off |
| Symbol | symbol | Any text |
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- limit or stop
- When order type is Limit or Stop, a price field appears (Limit price or Trigger price). On Market it is hidden.
- invalid
- A message in errors shows under its field with a warning icon. A quantity that is not a multiple of lotSize gets an error even if you pass none.
- submitting
- Pass submitting. The button shows a spinner, is marked busy and cannot be pressed again.
- disabled
- Pass disabled. Every field and the button lock, and disabledReason shows in words with a lock icon.
- focus
- The global focus ring shows on whichever field, segment or button you reach with the keyboard.
Tokens
Change one of these and every part that uses it follows.
--surface--surface-sunken--border--text--text-muted--danger-fg--radius-card
Built in
- It is a real form with a name. Enter in a field submits it, and a locked form does not.
- Each number field has a visible label, a hint where given and its error linked by aria-describedby.
- Side, order type and product are radio groups with arrow-key movement. Sell is a word, not just a colour.
- When locked, the fieldset is disabled and the reason is linked to the button.
- While submitting the button is marked busy and cannot be pressed again.
What you need to do
- Compute the summary rows yourself and keep them in words and numbers. This part does no money maths.
- Send errors in plain words, one per field. Do not rely on colour.
- When the app places the order, tell the person in text what happened.
- For an order an AI drafted, put this inside ActionDraft so the person must confirm.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide