TextField#

TextField is a text input. Maps to UI Toolkit's TextField.

Import#

import { TextField } from "onejs-react"

Basic Usage#

function NameInput() {
    const [name, setName] = useState("")

    return (
        <TextField
            value={name}
            onChange={(e) => setName(e.value)}
            placeholder="Enter your name"
        />
    )
}

Props#

PropTypeDescription
valuestringCurrent text value
placeholderstringPlaceholder text
multilinebooleanEnable multiline input
readOnlybooleanMake field read-only
maxLengthnumberMaximum character count
styleViewStyleInline styles (outer field)
classNamestringUSS class name(s) (outer field)
inputStyleViewStyleInline styles for the inner input
inputClassNamestringUSS class name(s) for the inner input
onChange(e) => voidValue change handler
onFocus(e) => voidFocus handler
onBlur(e) => voidBlur handler

Controlled Input#

function SearchBox() {
    const [query, setQuery] = useState("")

    const handleSearch = () => {
        console.log("Searching for:", query)
    }

    return (
        <View style={{ flexDirection: "row" }}>
            <TextField
                value={query}
                onChange={(e) => setQuery(e.value)}
                placeholder="Search..."
                style={{ flexGrow: 1, marginRight: 10 }}
            />
            <Button text="Search" onClick={handleSearch} />
        </View>
    )
}

Multiline#

<TextField
    value={description}
    onChange={(e) => setDescription(e.value)}
    placeholder="Enter description..."
    multiline={true}
    style={{ height: 100 }}
/>

Validation#

function EmailInput() {
    const [email, setEmail] = useState("")
    const [error, setError] = useState("")

    const validate = (value) => {
        if (!value.includes("@")) {
            setError("Please enter a valid email")
        } else {
            setError("")
        }
    }

    return (
        <View>
            <TextField
                value={email}
                onChange={(e) => {
                    setEmail(e.value)
                    validate(e.value)
                }}
                placeholder="Email address"
                style={{
                    borderColor: error ? "#ff0000" : "#333",
                }}
            />
            {error && <Label text={error} style={{ color: "#ff0000", fontSize: 12 }} />}
        </View>
    )
}

Password Field#

function PasswordInput() {
    const [password, setPassword] = useState("")

    return (
        <TextField
            value={password}
            onChange={(e) => setPassword(e.value)}
            placeholder="Password"
            // Note: UI Toolkit doesn't have a built-in password mask
            // You'd need to implement this with a custom element or USS
        />
    )
}

Styling the Inner Input#

A TextField is two elements: an outer field and an inner input, and the visible box (border, background, padding) lives on the inner one. style and className land on the outer field, so styling the box goes through inputStyle and inputClassName:

<TextField
    value={text}
    onChange={(e) => setText(e.value)}
    inputStyle={{
        backgroundColor: "#2a2a2a",
        borderWidth: 1,
        borderColor: "#444",
        borderRadius: 4,
        paddingTop: 10,
        paddingBottom: 10,
        paddingLeft: 12,
        paddingRight: 12,
        fontSize: 16,
        color: "#ffffff",
    }}
/>

inputClassName takes USS classes, Tailwind utilities included:

<TextField inputClassName="bg-gray-900 border-none rounded-lg" />

Inline inputStyle always wins, including over the theme's hover and focus rules. Classes win over the theme's resting look but not over its hover/focus, which use higher-specificity selectors; enable preflight to strip those, or use onejs-ui's Input, which handles all of it.