Reference
Behaviour reference
Every property on KeyboardBehavior — name, type, default, and what it does — grouped the way the type itself is.
KeyboardBehavior is one Sendable, Equatable, Codable value carrying every toggle the
engine exposes. It mirrors the native Settings ▸ Keyboard switches, and every default
reproduces the native keyboard — so the shortest correct integration is to pass nothing and
change nothing. There are 51 stored properties.
Where a default is a number, that number is the measured native value. Read it from the type rather than copying it into your own code, so a release that refines a measurement refines your keyboard with it.
var behavior = KeyboardBehavior.standard
behavior.autoCorrection = false
behavior.layoutTypeOverride = .dvorak
behavior.oneHandedMode = .right
behavior.translucentBackground = false
The two presets
.standard— the memberwise defaults, unchanged. Pure native..pressboardDefault— native with six deliberate changes, and whatPressboardConfigurationuses when you do not pass a behaviour:
| Property | .standard |
.pressboardDefault |
|---|---|---|
insertOnKeyDown |
false |
true |
uniformKeyColor |
false |
true |
nextKeyboardKey |
true |
false |
dictation |
true |
false |
multiTouchInputLayer |
false |
true |
predictiveKeyTargeting |
false |
true |
Every other property is identical in both.
Who applies what
Behaviours come in two kinds, and the Applied by column below says which:
- V — the engine view applies it itself. You set the flag and you are done.
- H — pure logic the engine provides and the host applies to the text document, because
the engine never owns the document.
PressboardControllerdoes this for you; a hand-built host calls the matching helper, each of which takes the flag asenabled:and no-ops when it is off. - V/H — both halves exist: the view produces something, the host acts on it.
Feedback and previews
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
characterPreview |
Bool |
true |
V | The enlarged character bubble on key press — native’s “Character Preview”. |
characterPreviewStyle |
CharacterPreviewStyle |
.native |
V | The shape of that bubble. See below. |
hapticFeedback |
Bool |
false |
V | Haptic tap on input. Needs Full Access in an extension. |
keySound |
Bool |
true |
V | The system key click, played by the engine itself. No host setup and no Full Access needed; silent on the Simulator. |
keyAnimationsEnabled |
Bool |
true |
V | Animate the visual feedback of a key press. false applies those transitions instantly instead. Does not touch the emoji panel. |
CharacterPreviewStyle
Five per-key pop shapes and three overlay styles:
| Case | Shape |
|---|---|
.native |
The real iOS key-pop, measured against a device: a detached rounded square floating above the pressed key, with no connecting neck, and the pressed key still visible underneath with its letter on it. |
.connected |
The engine’s previous .native: a larger key flaring out of the pressed key through a neck, with the pressed key blanking its letter into the pop. |
.curvy |
Connected, with a more pronounced curved neck. |
.square |
Connected, but angular — square head, straight neck, no rounding. |
.floating |
A detached rounded bubble above the key. Blanks the pressed key. |
.bubble |
Overlay: each press releases a translucent bubble carrying the letter, which drifts upward, bounces off walls and other bubbles, and pops. Does not block taps. |
.bubbleWord |
Overlay: the letters settle side by side on the keys-to-suggestions boundary and spell the word being typed. Ending the word pops the whole word and drops a separator bubble. |
.bubbleSentence |
Overlay: as .bubbleWord, but every character pops on its own short timer — a sliding tail of what you typed. |
.native‘s pop is taller than the connected styles’, so reserve headroom per active style with
NativeMetrics.popOverflow(for:) rather than the flat keyPopOverflow. Note the rename: a
persisted raw value of "native" now resolves to the re-measured shape. If you specifically want
the old connected one, store "connected".
Casing
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
autoCapitalization |
Bool |
true |
H | Capitalise at the start of a field, after . ! ? plus a space, and after a newline. AutoCapitalization.shouldCapitalizeNext(...). |
enableCapsLock |
Bool |
true |
V/H | Allow a double-tap on shift to lock caps. Passed to ShiftLogic.afterShiftTap(capsLockEnabled:). |
autoShiftToLowercase |
Bool |
true |
H | Drop a single shift back to lowercase after one character. Off makes a single shift sticky until tapped again. |
Text transforms
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
smartPunctuation |
Bool |
true |
H | Locale-aware curly quotes, the apostrophe, and -- to an em dash. SmartPunctuation.transform(...). |
periodShortcut |
Bool |
true |
H | A double space after a word expands to a period and a space. PeriodShortcut.shouldExpand(...). |
periodShortcutWindow |
TimeInterval |
0.8 |
H | How long after the first space a second one still expands. Native has such a window, and the default is what it measured as — raise it, lower it, or leave it alone. Independently of the window, a trailing space that was pasted or typed a minute ago never expands at all. Only matters with periodShortcut on. |
punctuationSpacing |
Bool |
true |
H | A stray space before a sentence mark is moved after it, so " ." becomes ". ". Also covers , ! ? ; :. |
emoticonAwarePunctuation |
Bool |
true |
H | Undo that move when the next character shows the mark opened an emoticon rather than a sentence — "hi :)" would otherwise come out "hi: )". Only : and ; can open one. |
suppressPunctuationSpacingAfterEdit |
Bool |
true |
H | If the user backspaces a spacing fixup away and retypes it their own way, do not reapply it at that spot. The same “the user rejected this” reasoning as suppressAutocorrectAfterEdit. |
spaceAfterPunctuation |
Bool |
false |
H | Insert a missing space when a letter is typed straight after a sentence mark, so "word.Next" becomes "word. Next". Not native, hence off. A backspace immediately after undoes it, so abbreviations and URLs stay typable. |
deleteByWord |
Bool |
true |
V/H | A backspace hold accelerates and then deletes whole words. The view escalates to .deleteWord; the host runs DeleteByWord. |
insertOnKeyDown |
Bool |
false |
V | Commit a character — and the space bar — on press rather than on release. A callout replaces it, a glide or a drag off the key undoes it, and a spacebar cursor drag undoes the space instead of typing one. |
Suggestions
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
predictiveText |
Bool |
true |
H | Show the suggestion bar and the provider’s suggestions. |
nextWordPrediction |
Bool |
true |
H | After a finished word, offer likely continuations instead of an empty bar. Comes from the injected NextWordPredicting; a no-op until something is learned or seeded. Only matters with predictiveText on. |
emptyFieldSuggestions |
Bool |
true |
H | Offer a few words in a field nobody has typed into yet, as native does. The words come from DictionarySuggestionProvider.openingWords. Only matters with predictiveText on. |
autoCorrection |
Bool |
true |
H | Replace the finished word with the primary correction on space. AutoCorrection.correction(...). |
autoCorrectMinimumWordLength |
Int |
2 |
H | The shortest word autocorrection may rewrite. Native never corrects a lone character. The locale rules in AutoCorrection.explicitCorrection are exempt, and tokens containing digits are never corrected. |
suppressAutocorrectAfterEdit |
Bool |
true |
H | Once a word has been corrected, backspacing into it stops it being corrected again until the user moves on. Native’s “I rejected the correction” behaviour. |
checkSpelling |
Bool |
true |
H | Feed the system spell checker. |
showMathResults |
Bool |
true |
H | Offer the result of a typed arithmetic expression in the bar, in the native three slots. MathResult.suggestionVariants(...). |
emojiSuggestions |
Bool |
true |
H | Suggest an emoji for the word being typed, e.g. “Hi” or “ahoj” to 👋. EmojiSuggestion.emoji(...). |
The bar is shared by the last three, so show and size it when any of predictiveText,
showMathResults or emojiSuggestions is on.
Appearance
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
theme |
KeyboardTheme |
.native |
V | The colour theme: .native, .midnight, .ocean, .sunset, .forest, .graphite. One palette recolours keys, text, accent, bubbles, callouts and the bar. Non-native themes are solid and force glass off. |
nativeDesignID |
String? |
nil |
H | Which measured snapshot of the native design to render. nil is automatic: the newest snapshot measured on an iOS no newer than the device’s. An id this build does not ship resolves back to automatic. |
translucentBackground |
Bool |
true |
V | Draw the keyboard on the iOS 26 translucent backdrop rather than a solid rectangle. Your extension’s views must also be clear. Forced off by a non-native theme. |
uniformKeyColor |
Bool |
false |
V | Fill every key, including shift, backspace, return, globe, mic and 123, with the letter-key colour instead of the darker native control colour. |
showSpaceLabel |
Bool |
true |
V | Show the word “space” on the space bar. Off leaves it blank, e.g. to show only a language indicator through keyOverlay. |
Input and layout
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
adaptToInputType |
Bool |
true |
V/H | Adapt to the field’s traits: an email field’s @ and ., a URL field’s .com, a digit pad, and the Go/Search/Send return label. Also suppresses the suggestion bar over a number, phone or decimal pad, where native shows none. The host feeds the traits. |
layoutTypeOverride |
KeyboardLayoutType? |
nil |
V | Force an arrangement: .qwerty, .qwertz, .azerty, .dvorak, .colemak. nil uses the locale’s default. |
returnToLettersAfterSpace |
Bool |
true |
H | After a space, newline or apostrophe on the 123 or #+= page, flip back to letters. LayoutAutoSwitch.nextType(...). |
nextKeyboardKey |
Bool |
true |
V | Show the globe key. Pass it to the resolver and handle .nextKeyboard. |
dictation |
Bool |
true |
V | Show the mic key. Handle .dictation; the host provides the speech-to-text. |
emojiKey |
Bool |
true |
V | Show the smiley key that switches to the emoji panel. |
emojiSearch |
Bool |
true |
V/H | Offer full-text emoji search — a search field in the emoji panel’s toolbar. |
Gestures and touch
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
slideToType |
Bool |
true |
V | Glide across keys to type a word, emitting .slideChanged and .slideTyped. |
slideToTypeRestoresDiacritics |
Bool |
true |
H | Insert a decoded glide with its dictionary diacritics restored (“máš”) rather than the folded form actually swiped (“mas”). Native does the latter; the default here diverges deliberately, since the accented word is the correct one and is free to restore once matched. Set it to false for exact parity. |
cursorDragUpdateInterval |
TimeInterval |
1/30 s |
H | How often, at most, a spacebar cursor drag pushes the caret to the host. Every push is a cross-process call, and a high-refresh display produces them faster than the host can repaint — push them all and the caret visibly vanishes mid-drag. 0 restores per-step pushing. |
spaceCommitsOnRelease |
Bool |
true |
H | Hold the space bar’s space until lift-off, so a press can still turn out to be a cursor drag rather than typing a space and deleting it again. Ordering is kept by flushing a held space as soon as another key commits. Only meaningful with insertOnKeyDown. |
cursorDragEngageHaptic |
Bool |
true |
H | A haptic tick the moment a spacebar press becomes a caret drag. Fires even when hapticFeedback is off — it marks a mode change, not a keystroke. Still needs Full Access in an extension. |
spaceBarTopExtension |
CGFloat |
12 |
H | How far above its own drawn top edge, in points, the space bar still claims a touch — the reason aiming at space never types a letter on the native keyboard. The default is the measured native value. It is space-bar-specific on purpose, not a global downward nudge; 0 restores a purely geometric space bar. |
multiTouchInputLayer |
Bool |
false |
V | Route key presses through a single shared multi-touch gesture instead of each key’s own DragGesture, so overlapping presses commit in real time order. Full parity with the per-key path. On in .pressboardDefault. |
touchHitTestVerticalOffset |
CGFloat |
0 |
V | Shift the effective hit-test point this many points up from the raw touch location. Only under multiTouchInputLayer. Native reportedly applies a similar correction, but we have not measured it — the default is therefore no correction at all, and anything else needs your own on-device verification. |
predictiveKeyTargeting |
Bool |
false |
V | Bias a borderline touch toward whichever same-row letter key keeps the word so far a viable dictionary prefix, as native does. Only under multiTouchInputLayer. Never reassigns a touch comfortably inside a key; a no-op at the start of a word or with no dictionary for the language. On in .pressboardDefault. |
One-handed mode
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
oneHandedMode |
OneHandedMode |
.off |
V | .left or .right shrinks the keys and shifts them toward that side. Handle onExpandOneHanded to return to full width. |
oneHandedScale |
CGFloat |
0.75 |
V | The fraction of the full width the keys occupy when one-handed. |
oneHandedGlobeMenu |
Bool |
true |
V | Long-pressing the globe opens a menu with a left/off/right picker above the system keyboard switcher, as native does. Supply nextKeyboardMenuRow. |
Diagnostics
| Property | Type | Default | Applied by | Meaning |
|---|---|---|---|---|
memoryDiagnosticsInterval |
Int |
0 |
H | Log the keyboard’s own memory footprint to the unified log every N keystrokes, or 0 to log nothing. Diagnostic only — see Performance. Costs one system call per interval and nothing else. |
Derived properties
Two computed properties are not part of the stored surface and are not encoded:
| Property | Type | Meaning |
|---|---|---|
resolvedNativeDesign |
NativeDesign |
The design snapshot this behaviour resolves to — nativeDesignID when it names one that ships, otherwise the one matching the running system. |
feedbackSettings |
FeedbackSettings |
The feedback subset — hapticFeedback and keySound — for the feedback trigger. |
A note on persistence
KeyboardBehavior decodes forward-compatibly: every key is optional and falls back to the same
default the memberwise initialiser uses. With synthesised Codable, adding a single property
would make all previously stored settings fail to decode — and a host persisting this in an
App Group would silently reset every choice its users had made, on every SDK update that added a
flag. It does not.
The style seam has one more knob that lives on the provider rather than on KeyboardBehavior:
keyFillPressed(for:) is the fill of a held key that has no key-pop of its own — backspace,
return, space, emoji, 123, globe, shift. It defaults to keyFill(for:), so a custom style that
does not override it has no pressed state there. See Theming.