WebberUI

Smooth Caret Input

An input with a spring-physics smooth caret — the custom caret glides to the text position on a spring, in bar, block, or underline shapes.

Loading preview…
npx shadcn@latest add https://webberui.com/r/smooth-caret-input.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

650
42
<SmoothCaretInput />

Installation

npx shadcn@latest add https://webberui.com/r/smooth-caret-input.json

The install also writes the --wb-duration-fast and --wb-ease-out CSS variables into your global stylesheet.

Usage

import { SmoothCaretInput } from "@/components/ui/smooth-caret-input";

<SmoothCaretInput
  placeholder="Start typing⋯"
  onChange={(value) => console.log(value)}
/>

Controlled mode:

const [value, setValue] = React.useState("");

<SmoothCaretInput value={value} onChange={setValue} caretShape="block" />

Props

PropTypeDefaultDescription
valuestringControlled value; when omitted, the component manages it internally (uncontrolled mode)
defaultValuestring""Initial value in uncontrolled mode
onChange(value: string) => voidFires when the value changes
placeholderstringPlaceholder text
disabledbooleanfalseDisables input
caretShape"bar" | "block" | "underline""bar"Caret shape
caretColorstringtext colourCaret colour (any CSS colour)
stiffnessnumber650Spring stiffness; higher settles faster
dampingnumber42Spring damping; higher springs back less
namestringThe input's name, for form submission
idstringThe input's id, for binding a label
aria-labelstringplaceholderAccessible label

How it works

  • Spring following: a hidden mirror span measures the width of the text before the caret to convert it into a pixel position, which useSpring then glides smoothly toward
  • Caret movement detection: it listens to selectionchange, so arrow keys, clicks, and selections all recompute the position immediately and pause the blink, which resumes once the glide finishes
  • Overflow handling: when the text exceeds the width and scrolls horizontally, scrollLeft is subtracted so the caret stays inside the visible area
  • IME safe: during Bopomofo (Zhuyin) or Pinyin composition, the mirror includes the composing text, so the caret keeps following the correct position

Accessibility

  • The custom caret carries aria-hidden so it does not interfere with screen reading; the input takes the aria-label / name / id
  • When the user has "reduce motion" enabled at the system level, the native caret is restored after mount and the spring and blink animations are disabled
  • When no aria-label is provided, the placeholder is used automatically, guaranteeing a readable name

On this page