Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Buttons

Pro

Input Button for React

A button that opens into a text field with its own submit button, for a signup or a search that stays small until it's wanted. For React with Base UI, when a form shouldn't take up room at rest.

Framework
UI library

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.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { InputButton } from "@/components/ui/input-button";
<InputButton
  placeholder="you@example.com"
  inputType="email"
  onValueSubmit={subscribe}
  submitLabel="Subscribe"
>
  Join the newsletter
</InputButton>

Demos

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.

Preview width

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.

Preview width

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.
Escape
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.

How do I change how it looks?

The closed button takes variant, size and pill like any button: it's an outline pill by default, and the field and the submit button follow its rounding and size. className styles the whole control, and --input-button-width sets how wide the field opens.

What happens with reduced motion?

It opens and closes at once, without sliding or fading. Focus moves the same way.

API Reference

InputButton

<div> data-slot="input-button"

PropType
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.

AttributeType
data-state?string

"open" when shown is true, otherwise "closed".

CSS variableType
--input-button-widthstring

The open field's width, submit button included (16rem).

All 35 buttons