> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Text input

> Modifiers that configure keyboard, style, submission, and focus for text fields

export const PlatformStatuses = ({statuses}) => {
  const StatusBadge = ({status, label}) => {
    const styles = {
      green: {
        backgroundColor: '#dcfce7',
        color: '#166534'
      },
      orange: {
        backgroundColor: '#fed7aa',
        color: '#9a3412'
      },
      red: {
        backgroundColor: '#fecaca',
        color: '#991b1b'
      },
      gray: {
        backgroundColor: '#f3f4f6',
        color: '#4b5563'
      }
    };
    const baseStyle = {
      display: 'inline-flex',
      alignItems: 'center',
      padding: '0.125rem 0.625rem',
      borderRadius: '9999px',
      fontSize: '0.875rem',
      fontWeight: '500'
    };
    const colorStyle = styles[status] || styles.green;
    return <span style={{
      ...baseStyle,
      ...colorStyle
    }}>
        {label || status}
      </span>;
  };
  const STATUS_CONFIG = {
    supported: {
      label: "Supported",
      color: "green"
    },
    partial: {
      label: "Partial",
      color: "orange"
    },
    "not-implemented": {
      label: "Not Implemented",
      color: "gray"
    }
  };
  const renderCard = (platform, value) => {
    if (!value) return null;
    const {status, note} = typeof value === "string" ? {
      status: value
    } : value;
    const config = STATUS_CONFIG[status];
    if (!config) return null;
    const titleMap = {
      ios: "SwiftUI",
      android: "Jetpack Compose",
      web: "Web"
    };
    return <Card key={platform} title={titleMap[platform] || platform}>
          <StatusBadge status={config.color} label={config.label} />
          {note && <div style={{
      marginTop: '0.5rem',
      fontSize: '0.875rem',
      color: '#6b7280'
    }}>
              {note}
            </div>}
      </Card>;
  };
  if (statuses == null) {
    return null;
  }
  return <Columns cols="3">
      {Object.entries(statuses).map(([platform, value]) => renderCard(platform, value))}
    </Columns>;
};

export const ComposeJS = ({code, name, height}) => {
  const encodedCode = useMemo(() => {
    if (!code) return "";
    try {
      return btoa(code);
    } catch (e) {
      console.error("Failed to encode code", e);
      return "";
    }
  }, [code]);
  if (!encodedCode) {
    return null;
  }
  return <iframe src={`https://www.metabind.ai/embed?code=${encodedCode}&name=${name ?? 'Example'}`} loading="lazy" style={{
    width: "100%",
    height: height || '350px',
    border: "1px solid #e5e7eb",
    borderRadius: "var(--rounded-2xl,1rem)",
    overflow: "hidden"
  }} title="ComposeJS Preview" />;
};

These modifiers tune the behavior of `TextField`, `SecureField`, and `TextEditor`. `keyboardType` and `submitLabel` adjust the on-screen keyboard; `textFieldStyle` sets the visual chrome; `autocorrectionDisabled` turns off autocorrect; `onSubmit` handles Return-key submission; `focused` binds programmatic focus.

These have no effect on non-input components. For multi-field forms, combine `submitLabel("next")` with `focused` to drive focus through fields as the user submits.

## keyboardType

Sets the keyboard type for text input fields.

```typescript theme={null}
.keyboardType(type: "default" | "asciiCapable" | "numbersAndPunctuation" | "URL" | "numberPad" | "phonePad" | "namePhonePad" | "emailAddress" | "decimalPad" | "twitter" | "webSearch" | "asciiCapableNumberPad"): Component
```

<ParamField path="type" type="string" required>
  The keyboard type to display. Options:

  * `"default"` — standard keyboard
  * `"asciiCapable"` — ASCII-only keyboard
  * `"numbersAndPunctuation"` — numbers and punctuation
  * `"URL"` — optimized for URL entry
  * `"numberPad"` — numeric keypad (0-9)
  * `"phonePad"` — phone number pad
  * `"namePhonePad"` — name and phone number
  * `"emailAddress"` — optimized for email entry
  * `"decimalPad"` — numbers with decimal point
  * `"twitter"` — optimized for Twitter/social (includes @ and #)
  * `"webSearch"` — optimized for web search
  * `"asciiCapableNumberPad"` — ASCII-capable numeric keypad
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: "not-implemented",
web: "not-implemented",
}}
/>

**Email input**

```typescript theme={null}
const body = () => {
    const [email, setEmail] = useState("")

    return TextField({ text: email, setText: setEmail })
        .keyboardType("emailAddress")
}
```

**Numeric input**

```typescript theme={null}
const body = () => {
    const [amount, setAmount] = useState("")

    return TextField({ text: amount, setText: setAmount })
        .keyboardType("decimalPad")
}
```

**URL input**

```typescript theme={null}
const body = () => {
    const [url, setUrl] = useState("")

    return TextField({ text: url, setText: setUrl })
        .keyboardType("URL")
}
```

This modifier only affects `TextField` and `TextEditor` components. It has no effect on non-input components. The keyboard type is a hint to the system — the actual keyboard displayed may vary by platform and locale.

## textFieldStyle

Sets the visual style for a TextField.

```typescript theme={null}
.textFieldStyle(style: "roundedBorder" | "plain" | "automatic"): Component
```

<ParamField path="style" type="&#x22;roundedBorder&#x22; | &#x22;plain&#x22; | &#x22;automatic&#x22;" required>
  The text field style:

  * `"roundedBorder"` — displays a rounded border around the field
  * `"plain"` — no visible border or background
  * `"automatic"` — uses the platform default style
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: "not-implemented",
web: "not-implemented",
}}
/>

**Rounded border style**

```typescript theme={null}
const body = () => {
    const [name, setName] = useState("")
    return TextField("Name", { text: name, setText: setName })
        .textFieldStyle("roundedBorder")
}
```

**Plain style**

```typescript theme={null}
const body = () => {
    const [query, setQuery] = useState("")
    return TextField("Search", { text: query, setText: setQuery })
        .textFieldStyle("plain")
}
```

**Form with styled fields**

```typescript theme={null}
const body = () => {
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")
    return VStack({ spacing: 12 }, [
        TextField("Email", { text: email, setText: setEmail })
            .textFieldStyle("roundedBorder")
            .keyboardType("emailAddress"),
        SecureField("Password", { text: password, setText: setPassword })
            .textFieldStyle("roundedBorder"),
    ]).padding(16)
}
```

## submitLabel

Sets the keyboard return key label for text input fields.

```typescript theme={null}
.submitLabel(label: "done" | "go" | "send" | "join" | "route"
    | "search" | "next" | "continue" | "return"): Component
```

<ParamField path="label" type="string" required>
  The label displayed on the keyboard's return key:

  * `"done"` — indicates completion
  * `"go"` — navigates to a URL or performs an action
  * `"send"` — sends a message
  * `"join"` — joins a group or session
  * `"route"` — starts navigation
  * `"search"` — performs a search
  * `"next"` — moves to the next field
  * `"continue"` — continues a multi-step process
  * `"return"` — the default return key
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: "not-implemented",
web: "not-implemented",
}}
/>

**Search field**

```typescript theme={null}
const body = () => {
    const [query, setQuery] = useState("")
    return TextField("Search...", { text: query, setText: setQuery })
        .submitLabel("search")
        .onSubmit(() => performSearch(query))
}
```

**Chat input**

```typescript theme={null}
const body = () => {
    const [message, setMessage] = useState("")
    return TextField("Message", { text: message, setText: setMessage })
        .submitLabel("send")
        .onSubmit(() => {
            sendMessage(message)
            setMessage("")
        })
}
```

**Multi-field form**

```typescript theme={null}
const body = () => {
    const [name, setName] = useState("")
    const [email, setEmail] = useState("")
    return VStack([
        TextField("Name", { text: name, setText: setName })
            .submitLabel("next"),
        TextField("Email", { text: email, setText: setEmail })
            .submitLabel("done"),
    ])
}
```

## autocorrectionDisabled

Disables autocorrection for text input fields.

```typescript theme={null}
.autocorrectionDisabled(isDisabled?: boolean)
```

<ParamField path="isDisabled" type="boolean" optional default="true">
  Whether autocorrection is disabled. Defaults to `true`.
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "supported" },
web: "not-implemented",
}}
/>

**Disable autocorrection on a username field**

```typescript theme={null}
const body = () => {
    const [username, setUsername] = useState("")
    return TextField({ text: username, setText: setUsername })
        .autocorrectionDisabled()
}
```

**Conditionally disable autocorrection**

```typescript theme={null}
const body = () => {
    const [text, setText] = useState("")
    return TextField({ text, setText })
        .autocorrectionDisabled(isCodeInput)
}
```

## onSubmit

Runs an action when the user submits a text field.

```typescript theme={null}
.onSubmit(action: () => void): Component
```

<ParamField path="action" type="() => void" required>
  A callback that runs when the user submits the text field (e.g., presses the Return key).
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: "not-implemented",
web: "not-implemented",
}}
/>

**Submitting a search**

```typescript theme={null}
const body = () => {
    const [query, setQuery] = useState("")

    return TextField({ text: query, setText: setQuery })
        .onSubmit(() => {
            console.log("Searching for: " + query)
        })
}
```

**Combined with submit label**

```typescript theme={null}
const body = () => {
    const [text, setText] = useState("")

    return TextField({ text: text, setText: setText })
        .submitLabel("search")
        .onSubmit(() => {
            performSearch(text)
        })
}
```

**Moving focus on submit**

```typescript theme={null}
const body = () => {
    const [name, setName] = useState("")
    const [email, setEmail] = useState("")
    const [emailFocused, setEmailFocused] = useState(false)

    return VStack([
        TextField({ text: name, setText: setName })
            .onSubmit(() => setEmailFocused(true)),
        TextField({ text: email, setText: setEmail })
            .focused({
                isFocused: emailFocused,
                setIsFocused: setEmailFocused
            })
    ])
}
```

The submit action is triggered when the user presses the Return key on the keyboard. Use [submitLabel](#submitlabel) to customize the Return key text (e.g., "search", "done", "go").

## focused

Binds focus state for programmatic focus control of text input fields.

```typescript theme={null}
.focused(props: { isFocused: boolean; setIsFocused: (value: boolean) => void })
```

<ParamField path="props" type="object" required>
  <Expandable title="props">
    <ParamField path="isFocused" type="boolean" required>
      Whether the component should be focused. Setting this to `true` moves focus to the component.
    </ParamField>

    <ParamField path="setIsFocused" type="(value: boolean) => void" required>
      A callback invoked when the focus state changes (e.g., when the user taps into or away from the field).
    </ParamField>
  </Expandable>
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: "not-implemented",
web: "not-implemented",
}}
/>

**Auto-focus a text field**

```typescript theme={null}
const body = () => {
    const [text, setText] = useState("")
    const [focused, setFocused] = useState(true)
    return TextField({ text, setText })
        .focused({ isFocused: focused, setIsFocused: setFocused })
}
```

**Focus on button tap**

```typescript theme={null}
const body = () => {
    const [query, setQuery] = useState("")
    const [isFocused, setIsFocused] = useState(false)
    return VStack([
        TextField({ text: query, setText: setQuery })
            .focused({
                isFocused: isFocused,
                setIsFocused: setIsFocused
            }),
        Button("Search", () => setIsFocused(true))
    ])
}
```

## See also

* [TextField](/bindjs/components/TextField) — text input component
* [SecureField](/bindjs/components/SecureField) — password input component
* [TextEditor](/bindjs/components/TextEditor) — multi-line text editor
* [disabled](/bindjs/modifiers/disabled) — disable a text field
