DesignInput

Text input component with Inter font, elevation shadows, and optional clear button. Extends native <input> attributes.

Import & Basic Usage

import { DesignInput } from "@/components/ui/design-input"

// Basic
<DesignInput placeholder="Enter text..." />

// Controlled with clear button
<DesignInput
  value={value}
  onChange={(e) => setValue(e.target.value)}
  clearable
  onClear={() => setValue("")}
/>

// With label
<DesignInput label="Username" placeholder="Enter username..." />

// Ghost variant (transparent, shows bg on hover/focus)
<DesignInput variant="ghost" placeholder="Click to edit..." />

Props

PropTypeDefaultDescription
size"small" | "default" | "large""default"Height: 28px / 32px / 40px
variant"default" | "ghost""default"ghost: transparent bg, shows on hover/focus
labelstring-Label text displayed above the input
clearableboolean-Show clear (x) button when input has value
onClear() => void-Callback when clear button is clicked (required with clearable)
startContentReactNode-Slot before the text input (e.g. search icon)
endContentReactNode-Slot after the text input (e.g. eye icon)
childrenReactNode-Replaces the entire <input> element (custom content mode)
dashedboolean-Dashed border style for empty/placeholder states
textAlign"left" | "center" | "right""left"Text alignment inside input
errorboolean-Error visual state
errorMessagestring-Error text inside input (right side, red)
showCountboolean-Show character count (requires maxLength)
maxLengthnumber-Max chars (CJK chars count as 2 when showCount enabled)
disabledboolean-Disabled state (44% opacity, surface-400 bg)
classNamestring-Applied to the outer wrapper div
refRef<HTMLInputElement>-Forwarded to the native <input> element

Right-side visibility priority: endContent > error+errorMessage > clearable. Only one shows at a time.

Size Variants

Small
28px
size="small"
Default
32px
(no size prop)
Large
40px
size="large"

States

Basic

Minimal usage

Props:
{ placeholder: "Enter text..." }

With Label

Label text above input

Props:
{ label: "Username" }

Clearable

clearable + onClear paired together

Props:
{ clearable: true, onClear: "() => setValue('')" }

Disabled

44% opacity, surface-400 bg

Props:
{ disabled: true }

Error

Red error text inside input (right side)

Props:
{ error: true, errorMessage: "Required" }
This field is required

Ghost Variant

Transparent bg, shows on hover/focus

Props:
{ variant: "ghost" }

Content Slots

startContent / endContent / children — three slots for custom content

startContent

Icon or text before input

Props:
{ startContent: "<DesignIcon name="search" />" }

endContent

Icon or text after input

Props:
{ endContent: "<DesignIcon name="eye" />" }

Both Sides

startContent + endContent together

Props:
{ startContent: "$", endContent: "USD" }
$
USD

children (Custom Content)

Replaces the entire <input> element

Props:
{ children: "<custom content>" }
Click to select a file...

Character Count

showCount + maxLength — CJK characters count as 2

Character Count

Displays "current/max" on the right

Props:
{ maxLength: 30, showCount: true }
0/30

Label + Count

Combine label with character count

Props:
{ label: "Title", maxLength: 50, showCount: true }
0/50

Usage Rules

  • 1.clearable must always pair with onClear callback to reset controlled state
  • 2.children replaces the entire <input> — no typing, no value, no onChange
  • 3.Right-side priority: endContent > error+errorMessage > clearable — only one shows at a time
  • 4.showCount requires maxLength — CJK characters are counted as 2
  • 5.className is applied to the outer wrapper div, not the <input> element
  • 6.All native input attributes work: placeholder, type, onChange, onKeyDown, autoFocus, etc.