Add addons, buttons, and helper content to inputs.
1<script lang="ts">
2 import {
3 InputGroup,
4 InputGroupAddon,
Installation
pnpm dlx sprawlify@latest add input-groupnpx sprawlify@latest add input-groupyarn sprawlify@latest add input-groupbunx --bun sprawlify@latest add input-group
Install the following dependencies:
pnpm add @sprawlify/primitives @sprawlify/sveltenpm install @sprawlify/primitives @sprawlify/svelteyarn add @sprawlify/primitives @sprawlify/sveltebun add @sprawlify/primitives @sprawlify/svelte
Add the following files to your project:
1export { default as InputGroup } from "./input-group.svelte";2export { default as InputGroupAddon } from "./input-group-addon.svelte";3export { default as InputGroupButton } from "./input-group-button.svelte";4export { default as InputGroupText } from "./input-group-text.svelte";5export { default as InputGroupInput } from "./input-group-input.svelte";6export { default as InputGroupTextarea } from "./input-group-textarea.svelte";71<script module lang="ts">
2import { cva, type VariantProps } from "class-variance-authority"
3import { cn } from "@/lib/utils"
4
5export const inputGroupAddonVariants = cva(
6 "text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none",
7 {
8 variants: {
9 align: {
10 "inline-start": "pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem] order-first",
11 "inline-end": "pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem] order-last",
12 "block-start":
13 "px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start",
14 "block-end":
15 "px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start",
16 },
17 },
18 defaultVariants: {
19 align: "inline-start",
20 },
21 }
22)
23</script>
24
25<script lang="ts">
26import { Sprawlify, type PolymorphicProps } from "@sprawlify/svelte"
27 import type { HTMLAttributes } from "svelte/elements";
28
29interface Props extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof inputGroupAddonVariants>, PolymorphicProps<"div"> {}
30
31let { class: className, align = "inline-start", children, ...rest }: Props = $props()
32</script>
33
34<Sprawlify
35 as="div"
36 role="group"
37 data-scope="input-group"
38 data-part="addon"
39 data-slot="input-group-addon"
40 data-align={align}
41 class={cn(inputGroupAddonVariants({ align }), className)}
42 onclick={(e) => {
43 if ((e.target as HTMLElement).closest("button")) {
44 return
45 }
46 e.currentTarget?.parentElement?.querySelector("input")?.focus()
47 }}
48 {...rest}
49>
50 {@render children?.()}
51</Sprawlify>1<script module lang="ts">
2import { cva } from "class-variance-authority"
3import { cn } from "@/lib/utils"
4
5export const inputGroupButtonVariants = cva(
6 "gap-2 text-sm shadow-none flex items-center",
7 {
8 variants: {
9 size: {
10 xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
11 sm: "",
12 "icon-xs": "size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
13 "icon-sm": "size-8 p-0 has-[>svg]:p-0",
14 },
15 },
16 defaultVariants: {
17 size: "xs",
18 },
19 }
20)
21</script>
22
23<script lang="ts">
24import { Button } from "@/components/ui/button"
25import type { VariantProps } from "class-variance-authority"
26import type { ComponentProps } from "svelte";
27
28interface Props extends Omit<ComponentProps<typeof Button>, "size">, VariantProps<typeof inputGroupButtonVariants> {}
29
30let { class: className, type = "button", variant = "ghost", size = "xs", ...rest }: Props = $props()
31</script>
32
33<Button
34 data-scope="input-group"
35 data-part="button"
36 type={type}
37 data-size={size}
38 variant={variant}
39 class={cn(inputGroupButtonVariants({ size }), className)}
40 {...rest}
41/>1<script lang="ts">
2import { cn } from "@/lib/utils"
3import { Input } from "@/components/ui/input"
4import type { HTMLInputAttributes } from "svelte/elements"
5
6interface Props extends HTMLInputAttributes {}
7
8let { class: className, ...rest }: Props = $props()
9</script>
10
11<Input
12 data-scope="input-group"
13 data-part="control"
14 data-slot="input-group-control"
15 class={cn("rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent flex-1", className)}
16 {...rest}
17/>1<script module lang="ts">
2import { cn } from "@/lib/utils"
3</script>
4
5<script lang="ts">
6import { Sprawlify, type PolymorphicProps } from "@sprawlify/svelte"
7import type { HTMLAttributes } from "svelte/elements"
8
9interface Props extends HTMLAttributes<HTMLSpanElement>, PolymorphicProps<"span"> {}
10
11let { class: className, children, ...rest }: Props = $props()
12</script>
13
14<Sprawlify
15 as="span"
16 data-scope="input-group"
17 data-part="text"
18 data-slot="input-group-text"
19 class={cn(
20 "text-muted-foreground gap-2 text-sm [&_svg:not([class*='size-'])]:size-4 flex items-center [&_svg]:pointer-events-none",
21 className
22 )}
23 {...rest}
24>
25 {@render children?.()}
26</Sprawlify>1<script lang="ts">
2import { cn } from "@/lib/utils"
3import { Textarea } from "@/components/ui/textarea"
4import type { HTMLTextareaAttributes } from "svelte/elements"
5import type { PolymorphicProps } from "@sprawlify/svelte";
6
7interface Props extends HTMLTextareaAttributes, PolymorphicProps<"textarea"> {}
8
9let { class: className, ...rest }: Props = $props()
10</script>
11
12<Textarea
13 data-scope="input-group"
14 data-part="control"
15 data-slot="input-group-control"
16 class={cn("rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent flex-1 resize-none", className)}
17 {...rest}
18/>1<script lang="ts">
2import { cn } from "@/lib/utils"
3import { Sprawlify, type PolymorphicProps } from "@sprawlify/svelte"
4import type { HTMLAttributes } from "svelte/elements";
5
6interface Props extends HTMLAttributes<HTMLDivElement>, PolymorphicProps<"div"> {}
7
8let { class: className, children, ...rest }: Props = $props()
9</script>
10
11<Sprawlify
12 as="div"
13 data-scope="input-group"
14 data-part="root"
15 data-slot="input-group"
16 role="group"
17 class={cn(
18 "border-input bg-input/30 dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 h-8 rounded-lg border transition-colors in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto",
19 className
20 )}
21 {...rest}
22>
23 {@render children?.()}
24</Sprawlify>Update the import paths to match your project setup.
Usage
1import {
2 InputGroup,
3 InputGroupAddon,
4 InputGroupButton,
5 InputGroupText,
6 InputGroupInput,
7 InputGroupTextarea
8} from "@/components/ui/input-group"1<InputGroup>
2 <InputGroupInput placeholder="Search..." />
3 <InputGroupAddon>
4 <SearchIcon />
5 </InputGroupAddon>
6</InputGroup>Examples
Block End
Use align="block-end" to position the addon below the input.
1<script lang="ts">
2 import { FieldGroup, Field, FieldLabel, FieldDescription } from "@/components/ui/field";
3 import {
4 InputGroup,
Block Start
Use align="block-start" to position the addon above the input.
1<script lang="ts">
2 import { FieldGroup, Field, FieldLabel, FieldDescription } from "@/components/ui/field";
3 import {
4 InputGroup,
Dropdown
1<script lang="ts">
2 import {
3 InputGroup,
4 InputGroupAddon,
Icon
1<script lang="ts">
2 import {
3 InputGroup,
4 InputGroupAddon,
Inline End
Use align="inline-end" to position the addon at the end of the input.
1<script lang="ts">
2 import { Field, FieldLabel, FieldDescription } from "@/components/ui/field";
3 import {
4 InputGroup,
Inline Start
Use align="inline-start" to position the addon at the start of the input. This is the default.
1<script lang="ts">
2 import { Field, FieldLabel, FieldDescription } from "@/components/ui/field";
3 import {
4 InputGroup,
Kbd
1<script lang="ts">
2import {
3 InputGroup,
4 InputGroupAddon,
Text
1<script lang="ts">
2 import {
3 InputGroup,
4 InputGroupAddon,
Textarea
1<script lang="ts">
2 import {
3 InputGroup,
4 InputGroupAddon,
On This Page
InstallationUsageExamplesBlock EndBlock StartDropdownIconInline EndInline StartKbdTextTextareaGet PRO
Need premium blocks and templates? Upgrade to PRO and get access.