Input Group
Add additional information or actions to an input or textarea.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupExample() -> impl IntoView { view! { <InputGroup class="max-w-xs"> <Input placeholder="Search..." /> <InputGroupAddon>{icon!(icondata::LuSearch)}</InputGroupAddon> <InputGroupAddon align="inline-end">"12 results"</InputGroupAddon> </InputGroup> } }
Inline Start
Icon positioned at the start.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupInlineStartExample() -> impl IntoView { view! { <Field class="max-w-sm"> <FieldLabel label_for="inline-start-input">"Input"</FieldLabel> <InputGroup> <Input id="inline-start-input" placeholder="Search..." /> <InputGroupAddon align="inline-start"> {icon!(icondata::LuSearch, class="text-muted-foreground")} </InputGroupAddon> </InputGroup> <FieldDescription>"Icon positioned at the start."</FieldDescription> </Field> } }
Inline End
Icon positioned at the end.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupInlineEndExample() -> impl IntoView { view! { <Field class="max-w-sm"> <Label label_for="inline-end-input">"Input"</Label> <InputGroup> <Input id="inline-end-input" input_type="password" placeholder="Enter password" /> <InputGroupAddon align="inline-end">{icon!(icondata::LuEyeOff)}</InputGroupAddon> </InputGroup> <FieldDescription>"Icon positioned at the end."</FieldDescription> </Field> } }
Block Start
Header positioned above the input.
Header positioned above the textarea.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupBlockStartExample() -> impl IntoView { view! { <FieldGroup class="max-w-sm"> <Field> <FieldLabel label_for="block-start-input">"Input"</FieldLabel> <InputGroup class="h-auto"> <Input id="block-start-input" placeholder="Enter your name" /> <InputGroupAddon align="block-start"> <InputGroupText>"Full Name"</InputGroupText> </InputGroupAddon> </InputGroup> <FieldDescription>"Header positioned above the input."</FieldDescription> </Field> <Field> <FieldLabel label_for="block-start-textarea">"Textarea"</FieldLabel> <InputGroup> <Textarea id="block-start-textarea" placeholder="console.log('Hello, world!');" class="font-mono text-sm" /> <InputGroupAddon align="block-start"> {icon!(icondata::LuFileCode, class="text-muted-foreground")} <InputGroupText class="font-mono">"script.js"</InputGroupText> <Button size="icon-xs" class="ml-auto"> {icon!(icondata::LuCopy)} <span class="sr-only">"Copy"</span> </Button> </InputGroupAddon> </InputGroup> <FieldDescription>"Header positioned above the textarea."</FieldDescription> </Field> </FieldGroup> } }
Block End
Footer positioned below the input.
Footer positioned below the textarea.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupBlockEndExample() -> impl IntoView { view! { <FieldGroup class="max-w-sm"> <Field> <FieldLabel label_for="block-end-input">"Input"</FieldLabel> <InputGroup class="h-auto"> <Input id="block-end-input" placeholder="Enter amount" /> <InputGroupAddon align="block-end"> <InputGroupText>"USD"</InputGroupText> </InputGroupAddon> </InputGroup> <FieldDescription>"Footer positioned below the input."</FieldDescription> </Field> <Field> <FieldLabel label_for="block-end-textarea">"Textarea"</FieldLabel> <InputGroup> <Textarea id="block-end-textarea" placeholder="Write a comment..." /> <InputGroupAddon align="block-end"> <InputGroupText>"0/280"</InputGroupText> <Button variant="default" size="sm" class="ml-auto"> "Post" </Button> </InputGroupAddon> </InputGroup> <FieldDescription>"Footer positioned below the textarea."</FieldDescription> </Field> </FieldGroup> } }
Icon
Display icons within input groups.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupIconExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-6"> <InputGroup> <Input placeholder="Search..." /> <InputGroupAddon>{icon!(icondata::LuSearch)}</InputGroupAddon> </InputGroup> <InputGroup> <Input input_type="email" placeholder="Enter your email" /> <InputGroupAddon>{icon!(icondata::LuMail)}</InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Card number" /> <InputGroupAddon>{icon!(icondata::LuCreditCard)}</InputGroupAddon> <InputGroupAddon align="inline-end">{icon!(icondata::LuCheck)}</InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Card number" /> <InputGroupAddon align="inline-end"> {icon!(icondata::LuStar)} {icon!(icondata::LuInfo)} </InputGroupAddon> </InputGroup> </div> } }
Text
Display additional text information alongside inputs.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupTextExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-6"> <InputGroup> <InputGroupAddon> <InputGroupText>"$"</InputGroupText> </InputGroupAddon> <Input placeholder="0.00" /> <InputGroupAddon align="inline-end"> <InputGroupText>"USD"</InputGroupText> </InputGroupAddon> </InputGroup> <InputGroup> <InputGroupAddon> <InputGroupText>"https://"</InputGroupText> </InputGroupAddon> <Input placeholder="example.com" class="!pl-0.5" /> <InputGroupAddon align="inline-end"> <InputGroupText>".com"</InputGroupText> </InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Enter your username" /> <InputGroupAddon align="inline-end"> <InputGroupText>"@company.com"</InputGroupText> </InputGroupAddon> </InputGroup> <InputGroup> <Textarea placeholder="Enter your message" /> <InputGroupAddon align="block-end"> <InputGroupText class="text-muted-foreground text-xs"> "120 characters left" </InputGroupText> </InputGroupAddon> </InputGroup> </div> } }
Button
Add buttons to perform actions within the input group.
use leptos::prelude::*; use singlestage::*; use std::time::Duration; #[component] pub fn InputGroupButtonExample() -> impl IntoView { let is_copied = RwSignal::new(false); let is_favorite = RwSignal::new(false); Effect::new(move || { if is_copied.get() { set_timeout(move || is_copied.set(false), Duration::from_secs(2)); } }); view! { <FieldGroup class="max-w-sm"> <Field> <InputGroup> <Input placeholder="https://x.com/shadcn" readonly=true /> <InputGroupAddon align="inline-end"> <Button aria_label="Copy" title="Copy" size="icon-xs" on:click=move |_| is_copied.set(true) > <Show when=move || is_copied.get() fallback=move || { icon!(icondata::LuCopy) } > {icon!(icondata::LuCheck)} </Show> </Button> </InputGroupAddon> </InputGroup> </Field> <Field> <InputGroup class="rounded-full"> <InputGroupAddon> <Popover> <PopoverTrigger> <Button class="rounded-full" variant="secondary" size="icon-xs"> {icon!(icondata::LuInfo)} </Button> </PopoverTrigger> <PopoverContent class="gap-1 text-sm max-w-2xs"> <p class="font-medium">"Your connection is not secure."</p> <p> "You should not enter any sensitive information on this site." </p> </PopoverContent> </Popover> </InputGroupAddon> <InputGroupAddon class="text-muted-foreground pl-1.5"> "https://" </InputGroupAddon> <Input id="input-secure-19" /> <InputGroupAddon align="inline-end"> <Button aria_label="Bookmark this page" title="Bookmark this page" class="rounded-full" on:click=move |_| is_favorite.set(!is_favorite.get()) size="icon-xs" > <Show when=move || is_favorite.get() fallback=move || { { icon!(icondata::LuStar) } } > {icon!(icondata::LuStar, class="fill-blue-600 stroke-blue-600")} </Show> </Button> </InputGroupAddon> </InputGroup> </Field> <Field> <InputGroup> <Input placeholder="Type to search..." /> <InputGroupAddon align="inline-end"> <Button aria_label="Search" title="Search" variant="secondary"> "Search" </Button> </InputGroupAddon> </InputGroup> </Field> </FieldGroup> } }
Kbd
Display a keyboard shortcut associated with the input.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupKbdExample() -> impl IntoView { view! { <InputGroup class="max-w-sm"> <Input placeholder="Search..." /> <InputGroupAddon> {icon!(icondata::LuSearch, class="text-muted-foreground")} </InputGroupAddon> <InputGroupAddon align="inline-end"> <Kbd>"⌘K"</Kbd> </InputGroupAddon> </InputGroup> } }
Dropdown
Pair input groups with dropdown menus for complex interactions.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupDropdownExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-4"> <InputGroup> <Input placeholder="Enter file name" /> <InputGroupAddon align="inline-end"> <DropdownMenu> <DropdownMenuTrigger> <Button aria_label="More" title="More"> {icon!(icondata::FiMoreHorizontal)} </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuItem>"Settings"</DropdownMenuItem> <DropdownMenuItem>"Copy path"</DropdownMenuItem> <DropdownMenuItem>"Open location"</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </InputGroupAddon> </InputGroup> <InputGroup class="[--radius:1rem]"> <Input placeholder="Enter search query" /> <InputGroupAddon align="inline-end"> <DropdownMenu> <DropdownMenuTrigger> <Button class="!pr-1.5 text-xs"> "Search In..." {icon!(icondata::LuChevronDown, class="size-3")} </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end" class="[--radius:0.95rem]"> <DropdownMenuItem>"Documentation"</DropdownMenuItem> <DropdownMenuItem>"Blog Posts"</DropdownMenuItem> <DropdownMenuItem>"Changelog"</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </InputGroupAddon> </InputGroup> </div> } }
Spinner
Show loading indicators while processing input.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupSpinnerExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-4"> <InputGroup> <Input placeholder="Searching..." /> <InputGroupAddon align="inline-end"> <Spinner /> </InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Processing..." /> <InputGroupAddon> <Spinner /> </InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Saving changes..." /> <InputGroupAddon align="inline-end"> <InputGroupText>"Saving..."</InputGroupText> <Spinner /> </InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Refreshing data..." /> <InputGroupAddon> <Spinner>{icon!(icondata::LuLoader)}</Spinner> </InputGroupAddon> <InputGroupAddon align="inline-end"> <InputGroupText class="text-muted-foreground">"Please wait..."</InputGroupText> </InputGroupAddon> </InputGroup> </div> } }
Textarea
Input groups also work with textarea components. Use block-start or block-end for alignment.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupTextareaExample() -> impl IntoView { view! { <div class="grid w-full max-w-md gap-4"> <InputGroup> <Textarea id="textarea-code-32" placeholder="console.log('Hello, world!');" class="min-h-[200px]" /> <InputGroupAddon align="block-end" class="border-t"> <InputGroupText>"Line 1, Column 1"</InputGroupText> <Button size="sm" class="ml-auto" variant="default"> "Run" {icon!(icondata::FiCornerDownLeft)} </Button> </InputGroupAddon> <InputGroupAddon align="block-start" class="border-b"> <InputGroupText class="font-mono font-medium"> {icon!(icondata::BiJavascript)} "script.js" </InputGroupText> <Button class="ml-auto" size="icon-xs"> {icon!(icondata::LuRefreshCw)} </Button> <Button variant="ghost" size="icon-xs"> {icon!(icondata::LuCopy)} </Button> </InputGroupAddon> </InputGroup> </div> } }
Tooltip
Add Add tooltips to provide additional context or help.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupTooltipExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-4"> <InputGroup> <Input placeholder="Enter password" input_type="password" /> <InputGroupAddon align="inline-end"> <Tooltip> <TooltipTrigger> <Button variant="ghost" aria_label="Info" size="icon-xs"> {icon!(icondata::LuInfo)} </Button> </TooltipTrigger> <TooltipContent> <p>"Password must be at least 8 characters"</p> </TooltipContent> </Tooltip> </InputGroupAddon> </InputGroup> <InputGroup> <Input placeholder="Your email address" /> <InputGroupAddon align="inline-end"> <Tooltip> <TooltipTrigger> <Button variant="ghost" aria_label="Help" size="icon-xs"> {icon!(icondata::FiHelpCircle)} </Button> </TooltipTrigger> <TooltipContent> <p>"We'll use this to send you notifications"</p> </TooltipContent> </Tooltip> </InputGroupAddon> </InputGroup> <InputGroup> <InputGroupAddon> <Tooltip> <TooltipTrigger> <Button variant="ghost" aria_label="Help" size="icon-xs"> {icon!(icondata::FiHelpCircle)} </Button> </TooltipTrigger> <TooltipContent side="left"> <p>"Click for help with API keys"</p> </TooltipContent> </Tooltip> </InputGroupAddon> <Input placeholder="Enter API key" /> </InputGroup> </div> } }
Label
Add labels within input groups to improve accessibility.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupLabelExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-4"> <InputGroup> <Input id="email" placeholder="shadcn" /> <InputGroupAddon> <Label label_for="email">"@"</Label> </InputGroupAddon> </InputGroup> <InputGroup> <Input id="email-2" placeholder="shadcn@vercel.com" /> <InputGroupAddon align="block-start"> <Label label_for="email-2" class="text-(--foreground)"> "Email" </Label> <Tooltip class="ml-auto"> <TooltipTrigger> <Button variant="ghost" aria_label="Help" class="rounded-full" size="icon-xs" > {icon!(icondata::LuInfo)} </Button> </TooltipTrigger> <TooltipContent> <p>"We'll use this to send you notifications"</p> </TooltipContent> </Tooltip> </InputGroupAddon> </InputGroup> </div> } }
Button Group
Wrap input groups with button groups to create prefixes and suffixes.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupButtonGroupExample() -> impl IntoView { view! { <div class="grid w-full max-w-sm gap-6"> <ButtonGroup> <ButtonGroupText> <Label label_for="url">"https://"</Label> </ButtonGroupText> <InputGroup> <Input id="url" /> <InputGroupAddon align="inline-end">{icon!(icondata::LuLink2)}</InputGroupAddon> </InputGroup> <ButtonGroupText>".com"</ButtonGroupText> </ButtonGroup> </div> } }
Anatomy
Import all parts and piece them together.
use leptos::prelude::*; use singlestage::*; #[component] pub fn InputGroupAnatomy() -> impl IntoView { view! { <InputGroup> <Input /> <InputGroupAddon> <InputGroupText /> </InputGroupAddon> </InputGroup> } }
API Reference
InputGroup
The main component that wraps inputs and addons.
| Name | Type | Default | Description |
|---|---|---|---|
| disabled | bool | false | Toggle whether or not this input group should appear disabled. |
InputGroupAddon
Displays icons, text, buttons, or other content alongside inputs.
| Name | Type | Default | Description |
|---|---|---|---|
| align | String | "inline-start" | Set how child content should be aligned. Accepted values are inline-start | inline-end | block-start | block-end. |
InputGroupText
A styled wrapper for displaying text and icons in an InputGroup.