Skip to content
v1.0.3

Input

A single-line text field wrapped in a bordered container that supports an optional leading icon, a trailing node, and an invalid state. The wrapper handles focus, hover, and disabled styling so the inner <input> stays clean.

bash
jlds add input

Usage

html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/input.css">

<div class="jl-input-wrap jl-input-wrap--md">
  <input class="jl-input" type="text" placeholder="[email protected]" />
</div>
vue
<script setup lang="ts">
import { ref } from "vue"
import { Input } from "@/components/ui/input"

const email = ref("")
</script>

<template>
  <Input v-model="email" placeholder="[email protected]" />
</template>
tsx
import { Input } from "@/components/ui/input"

<Input placeholder="[email protected]" />

Sizes

sm (32px) · md (38px, default) · lg (44px)

html
<div class="jl-input-wrap jl-input-wrap--sm"><input class="jl-input" placeholder="Small" /></div>
<div class="jl-input-wrap jl-input-wrap--md"><input class="jl-input" placeholder="Medium" /></div>
<div class="jl-input-wrap jl-input-wrap--lg"><input class="jl-input" placeholder="Large" /></div>
vue
<template>
  <Input size="sm" placeholder="Small" />
  <Input size="md" placeholder="Medium" />
  <Input size="lg" placeholder="Large" />
</template>
tsx
<Input size="sm" placeholder="Small" />
<Input size="md" placeholder="Medium" />
<Input size="lg" placeholder="Large" />

Icon & trailing

Add a leading icon or a trailing node (icon, button, or hint). In HTML, wrap each in a jl-input-adorn span on the correct side of the <input>.

html
<div class="jl-input-wrap jl-input-wrap--md">
  <span class="jl-input-adorn">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
    </svg>
  </span>
  <input class="jl-input" placeholder="Search" />
</div>

<div class="jl-input-wrap jl-input-wrap--md">
  <input class="jl-input" placeholder="Amount" />
  <span class="jl-input-adorn">USD</span>
</div>
vue
<template>
  <Input placeholder="Search">
    <template #icon><SearchIcon /></template>
  </Input>
  <Input placeholder="Amount">
    <template #trailing>USD</template>
  </Input>
</template>
tsx
import { Search } from "lucide-react"

<Input icon={<Search />} placeholder="Search" />
<Input trailing="USD" placeholder="Amount" />

Invalid & disabled

Add invalid for error styling (red border + danger focus ring) or disabled.

html
<div class="jl-input-wrap jl-input-wrap--md" data-invalid="true">
  <input class="jl-input" value="not-an-email" aria-invalid="true" />
</div>
<div class="jl-input-wrap jl-input-wrap--md" data-disabled="true">
  <input class="jl-input" value="Disabled" disabled />
</div>
vue
<template>
  <Input invalid model-value="not-an-email" />
  <Input disabled model-value="Disabled" />
</template>
tsx
<Input invalid defaultValue="not-an-email" />
<Input disabled defaultValue="Disabled" />

Props

React

Input extends React.InputHTMLAttributes<HTMLInputElement> (minus the native size), so type, placeholder, value, onChange, etc. all pass through.

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Control height and font size
iconReact.ReactNodeLeading icon node
trailingReact.ReactNodeTrailing node (icon, button, hint)
invalidbooleanfalseShow error styling

Vue

Input supports v-model; other attributes (type, placeholder, …) fall through to the inner <input>.

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Control height and font size
invalidbooleanfalseShow error styling
disabledbooleanfalseDisable the field
modelValuestring | numberBound value (v-model)

Slots: icon (leading), trailing (trailing).

CSS classes (HTML)

ClassPurpose
.jl-input-wrapBordered wrapper — handles focus/hover/disabled — always required
.jl-input-wrap--sm / --md / --lgSize
.jl-inputThe inner <input> element
.jl-input-adornLeading/trailing icon or text slot
[data-invalid="true"]Error styling (on the wrapper)
[data-disabled="true"]Disabled styling (on the wrapper)