SMS Autofill On Mobile
The code from the SMS appears above the keyboard on iOS and Android and fills every box with one tap.
NWD OTP Input (SMS Autofill & PIN) was built to give Bubble the verification code input it never had. It is built for sign-in, two-factor, and PIN flows, and brings one box per character, SMS code autofill on mobile, paste support, and a completed event together in one polished component. Fully customizable through 20+ properties, giving you complete control over every visual and behavioral detail.
Built for what Bubble does not cover.
Bubble has no verification code input. Building one by hand means a row of single-character inputs and workflows to move the cursor from box to box, handle backspace, split a pasted code across the boxes and notice when the last one is filled. The phone's SMS autofill rarely survives that setup, because it expects one field that asks for a one-time code.
The code from the SMS appears above the keyboard on iOS and Android and fills every box with one tap.
Pasting fills all the boxes at once, keeping only the characters the field accepts.
A dot in place of each typed character, for PINs and codes that should not stay on screen.
Fires the moment the last box is filled, so a workflow can verify the code with no extra click.
1 to 12 boxes, optional groups with a separator, and colors for the empty, filled and active boxes.
One real field behind the boxes, named and announced to screen readers, with a visible caret.
In detail
Place the plugin element wherever you need it.
Adjust the settings to match your use case, including the code length, the allowed characters, and the box styling.
Use the completed event to verify the code as soon as all boxes are filled, and read the exposed states to use them anywhere in your app.
Use completed to verify the code and value changed to save it. The first fires as soon as the last box is filled; the second fires whenever the code changes and is confirmed, including at that same moment.
Character shown in empty boxes (for example • or 0). Empty for none.
One character, shown in every empty box. Its color is Input placeholder color, in the empty state section.
Color of the placeholder text.
Number of characters of the code (1 to 12).
Characters accepted in each box. Numbers opens the numeric keyboard on mobile.
Numbers also opens the numeric keyboard on mobile. Letters and letters and numbers open the full keyboard.
Case applied to the letters as they are typed or pasted: uppercase, lowercase, or none to keep them as typed. Only applies when Allowed characters includes letters; numbers are not affected.
Shows a dot in place of each typed character, like a PIN.
Only what is shown is hidden: the `value` state keeps the real code.
Focuses the first box when the page loads.
Space between boxes, in pixels.
Corner radius of each box, in pixels.
Background color of the boxes that are still empty.
Border color of the boxes that are still empty.
Background color of the boxes that already have a character.
Border color of the boxes that already have a character.
Adds a separator after every N boxes (3 splits 6 boxes into 3 + 3). 0 for no groups.
The separator is drawn between the boxes and never enters the value.
Text shown between groups.
Font color of the group separator.
Code applied on load and on reset.
Disables the component, preventing any interaction.
Input background color when disabled.
Input border color when disabled.
Input font color when disabled.
Marks the field as required and enables input validation.
Input background color when invalid.
Input border color when invalid.
Background color of the active box while the input has focus: the one that receives the next character, or the last box when the code is complete.
Border color of the active box while the input has focus: the one that receives the next character, or the last box when the code is complete.
Name read by screen readers. When empty, uses the placeholder or the visible label.
Hint read by screen readers after the name. Empty for none.
Values the element exposes for the rest of the page to read.
A partly typed code is invalid even when the input is not required. Empty or complete are the only valid answers.
Typed code. Empty when no character was typed.
True when all boxes are filled.
True when the component is not disabled.
True when the input is marked as required.
True when the value is accepted. False when it is required and empty, or the code is incomplete, required or not. It updates on every change, so a workflow can rely on it; the invalid style only shows after the person leaves the field, or when a workflow sets the value.
True while the input has focus.
Where a workflow can start.
Triggered when the code changes and is confirmed: leaving the input, completing the code, resetting, or when a shorter code length or a new code type trims a code that was already typed or set.
Triggered when all boxes are filled, whether by typing, pasting, SMS autofill or the Set value action. When the person completes the code by typing, the field also leaves focus; clicking it again returns focus to the last box.
What a workflow can tell the element to do.
Restores the default code, or clears the boxes.
Focuses the first empty box.
Writes a code into the field from a workflow, keeping only valid characters up to the number of boxes, and refreshes the exposed states. A complete code also triggers the completed event.
Yes applies the value even while the element is disabled. No makes the action do nothing in that state.
The value to write into the field. It goes through the same treatment as a value typed by the user. An empty value clears every box.
Behind the boxes there is one real input marked as a one-time code field. iOS and Android recognize it and offer the code from an incoming SMS above the keyboard; one tap fills every box. Nothing has to be configured in the plugin, but the SMS has to contain the code in a form the phone recognizes, which most verification services already send.
Allowed characters takes numbers, letters, or both. Numbers opens the numeric keyboard on mobile. With letters, Text case turns them to uppercase or lowercase as they are typed, or keeps them as typed. Anything outside the chosen type is ignored, including in a pasted code.
completed fires when all the boxes are filled, whether typed, pasted, autofilled from the SMS or written by Set value, which is the moment to verify the code. Completing it by typing also takes the field out of focus, which closes the keyboard on mobile; clicking it again returns focus to the last box to correct it. value changed fires when the code changes and is confirmed: when the person leaves the field, completes the code or resets it, and when a shorter Code length trims a code that was typed or set.
The is valid state follows the code at every keystroke. The red style waits until the person leaves the field, and also shows when a workflow sets a code that is not accepted. An empty field is invalid only when This input is required? is checked; a partly typed code is invalid either way.
Yes. Group size adds a separator after every N boxes, so 3 splits six boxes into 3 + 3, and Group separator sets the text between the groups. The separator is only visual: the `value` state is the code without it.
Yes. The Set value action writes a code from anywhere in your app, with control over whether it applies while the input is disabled; Reset returns the field to its default value; and Focus puts the cursor in the first empty box. Focus on load? does the same when the page opens.
This plugin is maintained by GCS Studios and is part of the NWD UI - Input family, form controls built from scratch for Bubble, inspired by a personal component library originally built for React. Each one is carefully designed and tested in real applications before release, for the level of control, polish and reliability that native Bubble inputs often do not provide. See more plugins on the GCS Studios contributor page.
Each control here is drawn by the plugin instead of being restyled from a native one, so they match each other across the library and keep the same shape in every browser.