Build a Custom Keyboard Extension Template in SwiftUI
TL;DR
A custom keyboard on iOS is an app extension, a separate process that draws its own key layout and inserts text through the document proxy, not a view inside your app. You can host SwiftUI inside it, but the constraints shape everything: a tight memory budget, a required globe key to switch keyboards, and a Full Access prompt before it can use the network or shared storage. Start from a keyboard template so the layout, the proxy wiring, and the required keys are already in place.
A custom keyboard is an app extension
The first thing to understand about a custom keyboard is that it is not a view inside your app. It is an app extension, a separate process built on UIInputViewController, that the system loads into other apps when the user selects your keyboard. That boundary defines the whole project: your keyboard runs outside your app, with its own life cycle, its own tight memory budget, and no direct access to the host app beyond a narrow text interface. You can host SwiftUI inside the input view controller for the layout, but the controller and its constraints are the real container.
Internalizing that early saves a lot of confusion, because most custom-keyboard surprises come from treating it like a normal screen rather than a constrained extension living in someone else’s app.
Inserting text through the document proxy
A keyboard’s only window into the host app is the text document proxy. You do not read or write the app’s text fields directly; you call the proxy to insert text and delete backward, and you read its traits to adapt. The proxy tells you the keyboard type, whether to autocapitalize, and what the return key should say, so a well-behaved keyboard adjusts: a number pad for a number field, a “Go” return key in a search field, capitalization at the start of a sentence. It also exposes a little context around the cursor, which is enough for prediction but deliberately limited for privacy.
Treating the proxy as the entire contract keeps the keyboard honest. It can type and adapt; it cannot reach into the host app for anything the proxy does not offer.
The rules you cannot skip (globe key, Full Access)
Two requirements are non-negotiable. Every custom keyboard must include the globe key that switches to the next keyboard, so users are never trapped in yours, and omitting it is both a usability failure and a review problem. And anything beyond basic typing, network access, a shared container with your main app, even haptics, requires the user to grant Full Access, an explicit and slightly scary permission, so design the keyboard to work well without it and ask only when a feature truly needs it. Layouts also have to cope with the fact that text is enormous: Unicode defines more than 149,000 characters, so a keyboard exposes them through layers, categories, and long-press menus rather than a wall of keys, the same density problem a LINE-style sticker keyboard solves for stickers.
These are not optional polish. The globe key and the Full Access posture are what make a keyboard shippable and trustworthy.
Hosting SwiftUI in the keyboard
You can build the layout in SwiftUI by hosting it inside the input view controller, which gives you modern layout for the key grid, the popups, and any toolbar. The discipline is performance: the extension has far less memory headroom than an app, and a heavy SwiftUI hierarchy that rebuilds on every keystroke will get the keyboard terminated mid-type. So keep the key views light, avoid expensive work on each press, and treat the Apple keyboard guidance on sizing and layout as the baseline. The same extension-process discipline governs an iOS share extension, where the boundary and the memory limits are also the constraint.
Building it from a template
The key grid, the globe key, the shift and delete behavior, the proxy wiring, and the Full Access handling are the same in every custom keyboard, so they are worth starting from. A free VP0 design ships the keyboard layout, the keys, and the adaptive states with a machine-readable source page, so pasting the link into Claude Code or Cursor gives the agent the layout to wire to the input view controller and the document proxy. The text-and-AI angle continues in the Apple Intelligence on-device model, useful if your keyboard adds prediction.
Common mistakes building a custom keyboard
The recurring ones come from forgetting it is a constrained extension. Omitting the globe key traps users and fails review. Requiring Full Access for basic typing scares users off a permission you did not need. Building a heavy SwiftUI layout that rebuilds every keystroke gets the keyboard killed for memory. Ignoring the proxy traits ships a keyboard that does not adapt its return key or capitalization. And trying to reach the host app’s content beyond what the proxy offers chases access that does not exist.
Key takeaways: a custom keyboard extension
- It is an app extension, not a screen. A separate process on UIInputViewController, living in other apps.
- The document proxy is the only contract. Insert text, delete, and read traits to adapt; nothing more.
- The globe key and Full Access are required posture. Always include the switcher; ask for Full Access only when a feature needs it.
- Respect the memory budget. Keep SwiftUI light and avoid per-keystroke work, or the keyboard gets terminated.
- Start from a keyboard template. A free VP0 design gives an agent the layout and keys to wire to the input controller.
Frequently asked questions
How do I build a custom keyboard extension in SwiftUI? Create a keyboard app extension built on UIInputViewController and host your SwiftUI key layout inside it. Insert and delete text through the text document proxy rather than touching the host app directly, and read the proxy’s traits to adapt the keyboard type, capitalization, and return key. Always include the globe key to switch keyboards, ask for Full Access only when a feature genuinely needs the network or a shared container, and keep the layout light so the extension stays within its memory budget. A free keyboard template gives you the layout, the keys, and the proxy wiring to start from.
What is the safest way to build this with Claude Code or Cursor? Give the agent a keyboard-layout template and keep the extension rules explicit. A free VP0 SwiftUI design has a machine-readable source page with the key grid, the globe and delete keys, and the adaptive states, so Claude Code or Cursor wires it to the input view controller and the document proxy. That avoids the common result where an AI tool builds a heavy layout that gets terminated for memory, omits the required globe key, or demands Full Access for basic typing.
Can VP0 provide a free SwiftUI template for a custom keyboard? Yes. VP0 has free keyboard designs in SwiftUI with the key grid, the globe and delete keys, the shift behavior, and the adaptive states already built, each exposing an AI-readable source page. Because the layout exists, your agent wires it to a UIInputViewController and the text document proxy instead of reinventing the key layout and the proxy handling that usually trip up hand-built keyboards.
Does a custom keyboard need Full Access? Only for features beyond basic typing. Full Access is the permission that lets a keyboard use the network, share a container with your main app, or use haptics, and it is an explicit prompt users are right to be cautious about. Basic typing, switching keyboards, and a local layout work without it, so design the keyboard to be useful with Full Access off and request it only when a specific feature, like cloud prediction or sync, truly requires it. Demanding it up front for a simple keyboard drives users away.
What common errors happen when vibe coding a custom keyboard? Omitting the globe key so users are trapped, requiring Full Access for basic typing, and building a heavy SwiftUI layout that gets terminated for memory are the frequent ones. Ignoring the document proxy traits ships a keyboard that does not adapt its return key or capitalization, and trying to reach the host app beyond the proxy chases access that is not there. Include the switcher, keep the layout light, adapt from the proxy, and ask for Full Access only when a feature needs it.
Other questions from VP0 builders
How do I build a custom keyboard extension in SwiftUI?
Create a keyboard app extension built on UIInputViewController and host your SwiftUI key layout inside it. Insert and delete text through the text document proxy rather than touching the host app directly, and read the proxy's traits to adapt the keyboard type, capitalization, and return key. Always include the globe key to switch keyboards, ask for Full Access only when a feature genuinely needs the network or a shared container, and keep the layout light so the extension stays within its memory budget. A free keyboard template gives you the layout, the keys, and the proxy wiring to start from.
What is the safest way to build this with Claude Code or Cursor?
Give the agent a keyboard-layout template and keep the extension rules explicit. A free VP0 SwiftUI design has a machine-readable source page with the key grid, the globe and delete keys, and the adaptive states, so Claude Code or Cursor wires it to the input view controller and the document proxy. That avoids the common result where an AI tool builds a heavy layout that gets terminated for memory, omits the required globe key, or demands Full Access for basic typing.
Can VP0 provide a free SwiftUI template for a custom keyboard?
Yes. VP0 has free keyboard designs in SwiftUI with the key grid, the globe and delete keys, the shift behavior, and the adaptive states already built, each exposing an AI-readable source page. Because the layout exists, your agent wires it to a UIInputViewController and the text document proxy instead of reinventing the key layout and the proxy handling that usually trip up hand-built keyboards.
Does a custom keyboard need Full Access?
Only for features beyond basic typing. Full Access is the permission that lets a keyboard use the network, share a container with your main app, or use haptics, and it is an explicit prompt users are right to be cautious about. Basic typing, switching keyboards, and a local layout work without it, so design the keyboard to be useful with Full Access off and request it only when a specific feature, like cloud prediction or sync, truly requires it. Demanding it up front for a simple keyboard drives users away.
What common errors happen when vibe coding a custom keyboard?
Omitting the globe key so users are trapped, requiring Full Access for basic typing, and building a heavy SwiftUI layout that gets terminated for memory are the frequent ones. Ignoring the document proxy traits ships a keyboard that does not adapt its return key or capitalization, and trying to reach the host app beyond the proxy chases access that is not there. Include the switcher, keep the layout light, adapt from the proxy, and ask for Full Access only when a feature needs it.
Part of the Native Apple & SwiftUI: The iOS Ecosystem hub. Browse all VP0 topics →
Keep reading
Build a Stock Market Heat Map Grid UI in SwiftUI
A market heat map colors and sizes tiles by gain and market cap. Here is how to build the stock market heat map grid in SwiftUI, with an accessible color scale.
Build a Booking.com-Style Availability Calendar in SwiftUI
A Booking.com-style availability picker is more than a date picker. Here is how to build the availability calendar in SwiftUI, with real open and booked dates.
Build a Sideloading iOS App Install Animation in SwiftUI
In the EU, an alt-marketplace install is a real, system-gated flow. Here is how to build the sideloading install animation in SwiftUI, honestly.
Build a Smooth, Scrolling Social Media Feed in SwiftUI
A social media feed in SwiftUI is a scrolling list of post cards. Here is how to build it so it stays smooth with images, likes, and infinite scroll.
Build a Sora-Style AI Video Progress Bar in SwiftUI
AI video generation is slow and server-side, so honest progress beats a fake percentage. Here is how to build the Sora-style progress UI in SwiftUI.
Build a Starlink Dish Alignment Compass UI in SwiftUI
A dish alignment compass aims an antenna using the phone's heading and tilt. Here is how to build the Starlink dish alignment compass UI in SwiftUI with two sensors.