Skip to content
Blog

Inline Predictive Text in Flutter on iOS (Experimental)

What iOS inline predictive text is, how Flutter surfaces it via TextField.enableInlinePrediction and the keyboard properties, its experimental status, limits, and how to test it on device.

Published on • October 17, 2026

AI Assistant

iOS shows predicted words inside the text you are typing - greyed out ahead of the caret - and you accept them with the space bar. Native apps get this from the system keyboard. Flutter apps, until recently, did not: the composition zone simply did not appear, so a Flutter text field always felt a step behind the stock Messages or Notes field next to it.

Flutter now exposes that system behavior, behind an opt-in flag. This post explains what inline predictive text actually is at the UIKit level, exactly how Flutter surfaces it (TextField.enableInlinePrediction plus the familiar keyboard properties), what “experimental” means in practice for you, and how to turn it on and test it on a device.

What inline predictive text is

It is worth separating three related iOS keyboard behaviors, because documentation and blog posts tend to blur them:

  1. Predictive suggestions bar - the three tappable word candidates above the keyboard.
  2. Autocorrect - silent replacement of misspelled words as you type.
  3. Inline prediction - a grey ghost word rendered in the text stream itself, which you accept with Space or reject by continuing to type.

The third one is the new piece. UIKit models it as a property of UITextInputTraits, alongside the older switches: autocorrectionType, spellCheckingType, autocapitalizationType, smartQuotesType, smartDashesType, smartInsertDeleteType, keyboardType, textContentType, and so on. The relevant entry is inlinePredictionType, whose Apple documentation says it “controls whether system-provided text suggestions appear inline during typing”, that its default value is .default, and gives the canonical opt-out:

let textView = UITextView(frame: frame)
textView.inlinePredictionType = .no

Apple also notes the reason you would touch it: an app that provides its own suggestions should turn the system’s off so two completion systems do not fight over the same text field. .default means “whatever the system and the user’s settings decide” - which is why “off by default” and “settable to on/off” are not contradictions.

How Flutter surfaces it

Flutter’s What’s new in Flutter 3.44 announcement has a section titled “iOS predictive text (experimental)”:

We are introducing experimental support for native iOS inline predictive text for text input fields (#183650). This feature is off by default, but you can opt-in and test it by enabling TextField.enableInlinePrediction. When enabled, users typing in your app can accept iOS-predicted text (for example, typing “My n” and accepting “ame”) by pressing the Space key. Please note that the visual styling for this predictive text is still under active polish.

Three concrete facts from that paragraph: the flag lives on TextField, the feature is off unless you opt in, and accepting a prediction is the Space key.

The API reference for the property adds the platform contract:

final bool? enableInlinePrediction;
  • “Whether to enable inline predictive text.”
  • “This feature is specific to iOS 17 and later. It has no effect on other platforms.”
  • “By default, this property is null, which means inline prediction is disabled on iOS. Setting this flag overrides the platform behavior: when true, inline prediction is enabled; when false, it is disabled.”

That bool? with a null default is the design you want: null leaves the decision to the platform (currently: off inside Flutter), true forces it on, false forces it off. Cross-platform code can therefore pass null on Android, web and desktop without any branching.

Turning it on

TextField(
  controller: controller,
  enableInlinePrediction: true,   // iOS 17+ only; no effect elsewhere
  autocorrect: true,
  enableSuggestions: true,
  keyboardType: TextInputType.text,
  textInputAction: TextInputAction.done,
  decoration: const InputDecoration(labelText: 'Title'),
)

If you build fields through TextFormField, check that your Flutter version’s wrapper forwards the parameter - the flag is new, and form wrappers do not always gain new TextField parameters in the same release. Where it is not forwarded, drop to a TextField inside a FormField-style layout, or wrap the field in a platform view of your own only as a last resort.

The neighboring properties you should review at the same time

enableInlinePrediction sits in the same constructor block as the older input-behavior flags, and they interact in ways you want to decide deliberately rather than inherit:

PropertyTypeWhat it controls
enableInlinePredictionbool?iOS inline ghost word; null = platform default (disabled in Flutter), iOS 17+ only
autocorrectbool?Autocorrection; documented default is false on iOS when autofillHints contains password-related hints, otherwise true
enableSuggestionsboolWhether input suggestions are shown as the user types (default true)
smartQuotesTypeSmartQuotesType?Whether the platform auto-formats quotes
smartDashesTypeSmartDashesType?Whether the platform auto-formats dashes
keyboardTypeKeyboardTypeWhich system keyboard appears
textInputActionTextInputAction?The action/return key behavior

Practical consequences: a field with autocorrect: false and enableSuggestions: false is exactly the “app supplies its own suggestions” case Apple describes, so pairing it with enableInlinePrediction: true produces a field where two systems disagree - decide which one owns completion there. Password and one-time-code fields should keep prediction off (and usually inherit autocorrect: false via autofill hints anyway). smartQuotesType and smartDashesType are the fields to disable on code, URL and search inputs so don't and --flag survive typing.

Being honest about the experimental status

The feature is shipped behind an opt-in flag, marked experimental, with a tracked issue (#183650) and an explicit note that the visual styling is still being polished. Plan for that:

  • Do not ship it as a silent default across every field. Turn it on where typing speed matters - notes, message composition, search queries - and leave it null where precision matters.
  • Expect visual churn. The ghost text styling is rendered by the system inside Flutter’s editable region; if the caret, selection highlight or text scale interacts oddly, that is the polish work the team is asking feedback on, not necessarily your bug.
  • Behavior is per-platform and per-OS-version. iOS 17+ is the floor documented by the API. On older devices and every other platform the flag is a no-op, so your layout and validation must not depend on a prediction being accepted.
  • Accepting is Space. If your field uses Space for something else (a search box where space is meaningful data, or TextInputAction handling), verify the interaction - the user can always keep typing instead of accepting.
  • Feature flags belong behind a build switch. Gate it with a const so you can flip it off in one release if an iOS update changes behavior under you.

Testing it

You need real hardware behavior; a desktop run tells you nothing since the flag is iOS-only.

# Device must run iOS 17 or later
$ flutter devices
$ flutter run -d <device-id> --release

A short manual test script that catches the interesting cases:

  1. Launch with enableInlinePrediction: true, focus the field, type My n and confirm the ghost ame appears inline; press Space and confirm it is committed as ordinary text.
  2. Type a wrong continuation instead of Space and confirm the ghost disappears without corrupting the text.
  3. Toggle the flag to false in a hot reload and confirm the ghost stops appearing (this validates you are actually reaching the iOS path rather than a cached widget).
  4. Test with autocorrect off and suggestions off to see whether the two systems conflict in your specific field.
  5. Test at large text scale and with the keyboard’s one-handed mode, checking caret and selection rendering.
  6. Run the same field on Android and web to confirm nothing leaked into those platforms’ layouts.

Add a widget test for the plumbing - asserting the parameter reaches the TextField - but know that the rendering only ever gets verified on device. And since a bool? default of null means “platform decides”, a test asserting an exact keyboard state should pass the value explicitly rather than relying on defaults.

If you need the native behavior before Flutter’s version catches up

For apps that cannot wait, the escape hatch is the usual one: a platform channel that configures the underlying UITextInputTraits.inlinePredictionType on the native view hosting your text input, or a small plugin wrapping that view controller. That is real work - you own the API surface and the iOS version guards - so the pragmatic route is usually: enable enableInlinePrediction where it is safe, keep the field usable without predictions everywhere, and revisit once the styling work behind #183650 lands.

Checklist

  • enableInlinePrediction: true is set only on the fields where fast prose typing benefits, and stays null (platform default) elsewhere.
  • The field targets iOS 17+, and you have verified on a physical device that the ghost word appears and Space accepts it.
  • Password, one-time-code and precision fields (code, URLs) keep prediction/autocorrect off as a deliberate choice.
  • autocorrect, enableSuggestions, smartQuotesType and smartDashesType are reviewed together so two completion systems do not fight.
  • Your widget tests assert the flag reaches the TextField, and a manual pass covers rejection, hot-reload toggling, large text scale and other platforms.
  • The flag is behind a build-time switch so it can be disabled in one release if iOS behavior shifts.
  • You are tracking issue #183650 and know that visual styling is explicitly still in progress.

Sources: What’s new in Flutter 3.44, UITextInputTraits - UIKit, TextField.enableInlinePrediction API, TextField API, Flutter documentation