Giriş grubu
Arama çubukları, URL alanları ve sohbet oluşturucularındaki giriş alanlarına simgeler, düğmeler ve klavye ipuçları ekleyin — neobrütalist kenarlıklar ve gölgelerle.
import { Search } from "lucide-react"
import {Input group; bir giriş alanını veya metin alanını, eklentileriyle — simgeler, satır içi metin, düğmeler, klavye ipuçları — birlikte tek bir kenarlıklı kontrolün içine alır. Bu kitaplığın Input, Textarea ve Button bileşenlerinden oluşan yerleşik bir bileşimdir ve neobrütalist reçeteye göre stillendirilmiştir: kalın kenarlıklar, keskin gölgeler ve vurgulu tipografi.
Şu durumlarda tercih edin:
- Arama alanları — başta bir arama simgesi, sonda bir
⌘Kipucu veya temizleme düğmesi. - Önekli ve sonekli girişler — kullanıcıların yalnızca değişken kısmı yazması için sabit
https://,@veya.commetni. - Sohbet ve istem oluşturucular —
block-endkonumunda düğmelerden oluşan bir araç çubuğu ve gönderme eylemi içeren bir metin alanı.
Kurulum#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/input-group.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/input-group.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/input-group.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/input-group.json
Aşağıdaki kodu kopyalayıp projenize yapıştırın.
"use client"
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="input-group"
role="group"
className={cn(
"group/input-group relative flex h-8 w-full min-w-0 items-center rounded border-2 bg-input shadow-sm transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:outline-2 has-[[data-slot=input-group-control]:focus-visible]:outline-offset-2 has-[[data-slot=input-group-control]:focus-visible]:outline-primary has-[[data-slot][aria-invalid=true]]:border-destructive 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-[>textarea]:h-auto 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",
className
)}
{...props}
/>
)
}
const inputGroupAddonVariants = cva(
"flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
{
variants: {
align: {
"inline-start":
"order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]",
"inline-end":
"order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]",
"block-start":
"order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
"block-end":
"order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2",
},
},
defaultVariants: {
align: "inline-start",
},
}
)
function InputGroupAddon({
className,
align = "inline-start",
...props
}: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
return (
<div
role="group"
data-slot="input-group-addon"
data-align={align}
className={cn(inputGroupAddonVariants({ align }), className)}
onClick={(e) => {
if ((e.target as HTMLElement).closest("button")) {
return
}
e.currentTarget.parentElement?.querySelector("input")?.focus()
}}
{...props}
/>
)
}
const inputGroupButtonVariants = cva(
"flex items-center gap-2 text-sm shadow-none",
{
variants: {
size: {
xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
sm: "",
"icon-xs":
"size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
"icon-sm": "size-8 p-0 has-[>svg]:p-0",
},
},
defaultVariants: {
size: "xs",
},
}
)
function InputGroupButton({
className,
type = "button",
variant = "ghost",
size = "xs",
...props
}: Omit<React.ComponentProps<typeof Button>, "size"> &
VariantProps<typeof inputGroupButtonVariants>) {
return (
<Button
type={type}
data-size={size}
variant={variant}
className={cn(inputGroupButtonVariants({ size }), className)}
{...props}
/>
)
}
function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
className={cn(
"flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
/>
)
}
function InputGroupInput({
className,
...props
}: React.ComponentProps<"input">) {
return (
<Input
data-slot="input-group-control"
className={cn(
"flex-1 rounded-none border-0 bg-transparent shadow-none outline-none focus-visible:outline-none disabled:bg-transparent aria-invalid:outline-none dark:bg-transparent dark:disabled:bg-transparent",
className
)}
{...props}
/>
)
}
function InputGroupTextarea({
className,
...props
}: React.ComponentProps<"textarea">) {
return (
<Textarea
data-slot="input-group-control"
className={cn(
"flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none outline-none focus-visible:outline-none disabled:bg-transparent aria-invalid:outline-none dark:bg-transparent dark:disabled:bg-transparent",
className
)}
{...props}
/>
)
}
export {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupText,
InputGroupInput,
InputGroupTextarea,
}
İçe aktarma yollarını proje kurulumunuza uyacak şekilde güncelleyin.
Kullanım#
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
InputGroupTextarea,
} from "@/components/ui/input-group"<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>Kompozisyon#
Bir InputGroup oluşturmak için aşağıdaki kompozisyonu kullanın:
InputGroup
├── InputGroupInput or InputGroupTextarea
├── InputGroupAddon
├── InputGroupButton
└── InputGroupTextHizalama#
Eklentiyi girişe göre konumlandırmak için InputGroupAddon üzerinde align prop'unu kullanın.
Doğru odak yönetimi için, InputGroupAddon DOM'da her zaman InputGroupInput
veya InputGroupTextarea'dan sonra yerleştirilmelidir. Eklentiyi görsel olarak
konumlandırmak için align prop'unu kullanın.
inline-start#
Eklentiyi girişin başında konumlandırmak için align="inline-start" kullanın. Bu varsayılandır.
import { SearchIcon } from "lucide-react"
import {inline-end#
Eklentiyi girişin sonunda konumlandırmak için align="inline-end" kullanın.
import { EyeOffIcon } from "lucide-react"
import {block-start#
Eklentiyi girişin üstünde konumlandırmak için align="block-start" kullanın.
import { CopyIcon, FileCodeIcon } from "lucide-react"
import {block-end#
Eklentiyi girişin altında konumlandırmak için align="block-end" kullanın.
import {
Field,
FieldDescription,Örnekler#
Simge#
import {
CheckIcon,
CreditCardIcon,Metin#
import {
InputGroup,
InputGroupAddon,Düğme#
"use client"
import * as React from "react"Kbd#
import { SearchIcon } from "lucide-react"
import {Açılır Menü#
"use client"
import { ChevronDownIcon, MoreHorizontal } from "lucide-react"Spinner#
import { LoaderIcon } from "lucide-react"
import {Textarea#
import {
IconBrandJavascript,
IconCopy,Özel Giriş#
Otomatik odak durumu yönetimi için özel girişinize data-slot="input-group-control" özniteliğini ekleyin.
İşte üçüncü taraf bir kitaplıktan yeniden boyutlandırılabilir özel bir textarea örneği.
"use client"
import TextareaAutosize from "react-textarea-autosize"RTL#
Neobrutalism'de RTL desteğini etkinleştirmek için RTL yapılandırma kılavuzuna bakın.
"use client"
import * as React from "react"Erişilebilirlik#
Input group için bir ARIA bileşen deseni yoktur — sarmalayıcı, yardımcı teknolojilerin eklentileri kontrolle ilişkilendirmesi için role="group" olarak işlenir; klavye erişimi ise yereldir: Tab, giriş alanına ve tüm InputGroupButton öğelerine DOM sırasıyla ulaşır — eklentilerin giriş alanından sonra yer almasının (görsel konumun align ile ayarlanmasının) nedeni budur. İki şey size kalır: https:// gibi eklenti metni görseldir, programatik bir etiket değildir; bu yüzden giriş alanı yine de bir <Label> veya aria-label gerektirir. Yalnızca simgeden oluşan düğmeler de aria-label gerektirir — bir eklentiye tıklamak giriş alanını odaklar, ama bu bir işaretçi kolaylığıdır, klavye yolu değildir.
API Referansı#
InputGroup#
Girişleri ve eklentileri sarmalayan ana bileşen.
| Prop | Type | Default |
|---|---|---|
className | string |
<InputGroup>
<InputGroupInput />
<InputGroupAddon />
</InputGroup>InputGroupAddon#
Girişlerin yanında simgeler, metin, düğmeler veya diğer içerikleri görüntüler.
Doğru odak gezinmesi için, InputGroupAddon bileşeni girişten sonra
yerleştirilmelidir. Eklentiyi konumlandırmak için align prop'unu ayarlayın.
| Prop | Type | Default |
|---|---|---|
align | "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" |
className | string |
<InputGroupAddon align="inline-end">
<SearchIcon />
</InputGroupAddon><InputGroupInput /> için inline-start veya inline-end hizalamasını kullanın. <InputGroupTextarea /> için block-start veya block-end hizalamasını kullanın.
InputGroupAddon bileşeni birden fazla InputGroupButton bileşeni ve simge içerebilir.
<InputGroupAddon>
<InputGroupButton>Button</InputGroupButton>
<InputGroupButton>Button</InputGroupButton>
</InputGroupAddon>InputGroupButton#
Giriş grupları içinde düğmeler görüntüler.
| Prop | Type | Default |
|---|---|---|
size | "xs" | "icon-xs" | "sm" | "icon-sm" | "xs" |
variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "ghost" |
className | string |
<InputGroupButton>Button</InputGroupButton>
<InputGroupButton size="icon-xs" aria-label="Copy">
<CopyIcon />
</InputGroupButton>InputGroupInput#
Giriş grupları oluştururken <Input /> yerine kullanılır. Bu bileşen, giriş grubu stilleri önceden uygulanmış olarak gelir ve odak durumu yönetimi için birleşik data-slot="input-group-control" değerini kullanır.
| Prop | Type | Default |
|---|---|---|
className | string |
Diğer tüm prop'lar, alttaki <Input /> bileşenine iletilir.
<InputGroup>
<InputGroupInput placeholder="Enter text..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>InputGroupTextarea#
Giriş grupları oluştururken <Textarea /> yerine kullanılır. Bu bileşen, textarea grubu stilleri önceden uygulanmış olarak gelir ve odak durumu yönetimi için birleşik data-slot="input-group-control" değerini kullanır.
| Prop | Type | Default |
|---|---|---|
className | string |
Diğer tüm prop'lar, alttaki <Textarea /> bileşenine iletilir.
<InputGroup>
<InputGroupTextarea placeholder="Enter message..." />
<InputGroupAddon align="block-end">
<InputGroupButton>Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>