shadcn.io is not affiliated with official shadcn/ui
At rest it's a button with a small arrow at its end. Press it and a text field with a submit button slides open in its place, and focus moves straight into the field. Enter or the submit button sends what was typed to onValueSubmit; Escape, or focus leaving the field and its buttons, folds it back into the button.
Use it for a newsletter signup in a footer, an inline search in a toolbar, or adding a tag, where a full form would crowd the layout. When the field is the main thing on the page, show it from the start instead. The button is the Button, so variant and size work as usual, and the field is the Input. The field opens with a CSS grid transition, from a 0fr column to 1fr, while the button fades, with no animation library and nothing measured; with reduced motion it opens and closes at once.
Installation
Usage
import { InputButton } from "@/components/ui/input-button";<InputButton
placeholder="you@example.com"
inputType="email"
onValueSubmit={subscribe}
submitLabel="Subscribe"
>
Join the newsletter
</InputButton>Demos
Search
icon replaces the arrow on the closed button, here with a magnifying glass, and the --input-button-width CSS variable sets how wide the field opens, here 20rem instead of the default 16rem, from className. submitLabel names the submit button, and inputType and placeholder set up the field.
Controlled
Pass open and onOpenChange to hold the state yourself. Here onValueSubmit adds the tag and closes the field, which sends focus back to the button so the next tag is one press away.
Accessibility
Closed, it's a plain button. When it opens, focus moves into the field, and the closed button is made inert so it can't be reached while hidden; closed, the field is inert instead. The field is labelled by the button's text unless you pass inputLabel, which is better when the button's text isn't a name for the field, such as Email address for Join the newsletter. Escape closes it and puts focus back on the button; tabbing or clicking away closes it and leaves focus where it went. The arrow icon is hidden from assistive tech.
- Enter
- On the button, open the field. In the field, submit.
- Space
- On the button, open the field.
- Tab
- Move from the field to the submit button.
- EscEscape
- Close the field and return focus to the button.
- Shift+Tab
- From the field, move out and close it.
FAQ
How do I get what was typed?
onValueSubmit receives it as a string when someone presses Enter or the submit button. It's read when submitted, so nothing re-renders while someone types.
Why does it stay open after submitting?
So you can show an error and let people fix it. To close it after a successful submit, control it with open and onOpenChange and set open to false in onValueSubmit, as the Controlled demo does.
Can I put it inside my own form?
Yes. It doesn't render a form of its own, so it never submits yours: Enter in its field and its submit button only call onValueSubmit. Give the field an inputName and it's sent with your form too.
What label does the field get?
The button's text. Pass inputLabel when the field needs its own name, such as Email address.
How wide does it get?
16rem by default, the submit button included. Set the --input-button-width CSS variable for another, from className ([--input-button-width:20rem]) or your stylesheet.
API Reference
InputButton
<div> data-slot="input-button"
open?boolean
Whether it's open, when you hold it yourself. Pair it with onOpenChange.
defaultOpen?boolean
Whether it starts open, as a field, when you don't pass open.
- Default
false
onOpenChange?(open: boolean) → void
Called when it opens or closes, with the new state.
- Parameters
open– boolean- Returns
void
children?ReactNode
The button's label; it also names the field once it opens.
focusableWhenDisabled?boolean
Whether the button should be focusable when disabled.
- Default
false
icon?ReactNode
The icon at the end of the closed button, hinting that it opens into a
field. Ark default: <ArrowRightIcon />.
- Default
<ArrowRightIcon aria-hidden="true" className="rtl:-scale-x-100" />
inputLabel?string
The field's accessible name, when the button's label doesn't say what to type (a search button labelled with an icon).
inputName?string
The field's name, for a form that reads it.
inputType?"email" | "search" | "tel" | "text" | "url"
The field's type, for the keyboard a phone shows.
- Type
"email" | "search" | "tel" | "text" | "url"- Default
"text"
nativeButton?boolean
Whether the component renders a native <button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).
- Default
true
onValueSubmit?(value: string) → void
Called with what was typed when it's submitted, with Enter or the
submit button. It stays open: close it here with open if you want.
- Parameters
value– string- Returns
void
pill?boolean
Round ends on the button, the field and the submit button.
- Default
true
placeholder?string
The field's placeholder, such as you@example.com.
submitLabel?ReactNode
The submit button's label, beside the open field.
- Default
"Submit"
variant?ButtonProps["variant"]
The closed button's look; the submit button keeps the default one.
- Default
"outline"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
data-state?string
"open" when shown is true, otherwise "closed".
--input-button-widthstring
The open field's width, submit button included (16rem).
Related
Kbd Button
ControlsOpen a search from the keyboard
Loading Button
Progress & resultsShow progress while the submit runs
- Pro
Success Button
Progress & resultsConfirm the signup went through
- Pro
Counter Button
ControlsAnother control that takes a value
Arrow Button
Hover revealsThe same pill with an arrow cue
Copy Button
Progress & resultsInline action that answers in place