Caret

A blinking text caret — a pure motion atom or a fully controlled bar

A text caret: a thin vertical bar you can drive two ways. Pass a controlled opacity and it renders exactly that (let the surrounding component decide when the caret shows), or set blink and it blinks deterministically from useCurrentFrame(). Safe in Remotion's headless per-frame renderer (no Date, Math.random, or requestAnimationFrame).

It is the shared caret behind the input primitive and the claude-chat composition.

Installation

$ pnpm dlx shadcn@latest add @remocn/caret

Usage

Controlled — the consumer decides visibility (e.g. a typing state machine):

import { Caret } from "@/components/remocn/caret";

export const Scene = () => (
  <Caret color="#1F1E1D" height={24} opacity={typing ? 1 : 0} />
);

Standalone blink — a self-animating caret:

import { Caret } from "@/components/remocn/caret";

export const Scene = () => <Caret blink blinkPerSecond={1} height={28} />;
visible = floor(frame × speed / halfPeriod) is even
halfPeriod = fps / blinkPerSecond / 2

When opacity is provided it always wins; otherwise blink drives the bar, and with neither the caret stays solid.

Props

PropTypeDefaultDescription
color
string"currentColor"Bar fill color. Defaults to currentColor so it inherits the surrounding text color.
width
number2Bar width in px.
height
number18Bar height in px.
radius
number1Corner radius in px.
opacity
numberControlled opacity. When set, it overrides blink and renders exactly this value.
blink
booleanfalseWhen true and opacity is unset, the caret blinks on the timeline.
blinkPerSecond
number1Full on/off blink cycles per second.
speed
number1Scales the playhead used for blinking. speed=2 blinks twice as fast.
marginLeft
number0Left gap in px, useful to space the caret after revealed text.
className
stringOptional className passed to the span.
style
CSSPropertiesOptional style overrides merged last (e.g. vertical alignment offsets).