UIButton, UIInput & UITextArea
The three elements that take user input. UIButton is the only tappable container — touch
handlers exist solely on UIButton, UIScreen, and UIWidget (see
Pointer events); to make anything clickable (a card, a list row, an icon),
wrap it in a UIButton. UIInput is a single-line text field, UITextArea its multi-line
sibling.
At a glance
let input: UIInput
const form = UIColumn([
input = UIInput()
.style({ height: 40, px: 12, borderRadius: 8, bgColor: "white", color: "black",
placeholder: "Your name", placeholderColor: "#999" })
.onChange(v => console.log("typing:", v)),
UIButton([ UIText("Submit").style({ color: "white" }) ])
.style({ height: 40, justifyContent: "center", bgColor: "#FF4032", borderRadius: 8,
onPressed: { opacity: 0.7 }, rippleColor: "default" })
.onClick(() => console.log("submitted:", input.value)),
]).style({ gap: 8 })UIButton
UIButton(): UIButton
UIButton(children: UINodeChild[]): UIButtonA container that acts as a UIRow with vertically centered children. Full container surface:
.append / .insert / .remove / .setContent, .style, .animateTo / .animateFrom,
.onLayout. Use flexDirection: "column" for a card-shaped button.
button.onClick(ev => …) // pointer-up over the button; ev: ClickEvent
button.onTouchStart(ev => …) // pointer-down; ev.track({...}) starts a drag gesture
button.isPressed(): boolean // true while a finger is currently down on the buttononClick / onTouchStart events carry clientX / clientY / pointerId (logical px). Drags —
ev.track(), claim — work exactly as described in Pointer events.
buttons render no chrome of their own — style them like any container (bgColor,
borderRadius, padding). Give a button an explicit height: on its own it is only as tall as
its text.
Press feedback — opt-in
button.style({
onPressed: { opacity: 0.7, bgColor: "#c22", duration: 150 }, // style while pressed
rippleColor: "default", // Android ripple; or any Color
})Nothing happens visually on press unless you ask. onPressed accepts drawable/base styles
(bgColor, opacity, border*, transform, …) applied while the finger is down, plus an
optional transition duration (ms). rippleColor is Android-only and replaces the
onPressed visual there — so setting both gives a ripple on Android and the onPressed style on
iOS.
For a persistent visual state you toggle yourself (selected, checked, active) rather than one the
system drives, declare a style class ($name) and flip it with setClass/toggleClass — see
Style classes. onPressed always wins over a class while pressed.
UIInput & UITextArea
UIInput(): UIInput // single-line field
UITextArea(): UITextArea // multi-lineinput.value // get/set the current text (a content property, not a style)
input.onChange(cb: (value: string) => void): this // every edit
input.onFocus(cb: () => void): this
input.onBlur(cb: () => void): thisInput-specific styles, on top of the usual element + text styles (fontSize, color,
fontFamily, …):
input.style({
placeholder: "Search…",
placeholderColor: "#999",
type: "search", // "text" (default) | "password" | "search"
onFocused: { borderColor: "#FF4032", duration: 150 }, // style while focused (like onPressed)
})give inputs an explicit height and a flexGrow: 1 (in a row) or width — an input
collapses to its placeholder's width and its text's height, it does not stretch like a web
<input>.
there is no submit event — no onSubmit, no enter-key callback. The pattern is a
Send/Submit UIButton next to the field that reads input.value.
Pitfalls
// ✗ touch handler on a plain container
UIColumn([...]).onTouchStart(cb) // no such method — only UIButton/UIScreen/UIWidget
// ✓ wrap in a UIButton
UIButton([...]).onTouchStart(cb)
// ✗ button next to a 40px input shrinks to its text height
UIRow([ input.style({ height: 40 }), UIButton([icon]) ])
// ✓ give controls the same explicit height
UIRow([ input.style({ height: 40 }), UIButton([icon]).style({ height: 40 }) ])See also
- Pointer events & gestures — event objects,
ev.track(),claim - Styling —
.style(), style states,animateTo - Containers —
UIRow/UIColumnlayout rules a button inherits