# Caret
URL: https://remocn.dev/docs/ui/components/caret

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

- Install: `npx shadcn@latest add @remocn/caret`
- Vibe: tech
- Natural length: 120f @ 30fps

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

```bash
npx shadcn@latest add @remocn/caret
```

## Usage

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

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

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

Standalone blink — a self-animating caret:

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

export const Scene = () => <Caret blink blinkPerSecond={1} height={28} />;
```

## How blink works

```
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

| Prop | Type | Default | Description |
|---|---|---|---|
| `color` | `string` | `"currentColor"` | Bar fill color. Defaults to currentColor so it inherits the surrounding text color. |
| `width` | `number` | `2` | Bar width in px. |
| `height` | `number` | `18` | Bar height in px. |
| `radius` | `number` | `1` | Corner radius in px. |
| `opacity` | `number` | — | Controlled opacity. When set, it overrides blink and renders exactly this value. |
| `blink` | `boolean` | `false` | When true and opacity is unset, the caret blinks on the timeline. |
| `blinkPerSecond` | `number` | `1` | Full on/off blink cycles per second. |
| `speed` | `number` | `1` | Scales the playhead used for blinking. speed=2 blinks twice as fast. |
| `marginLeft` | `number` | `0` | Left gap in px, useful to space the caret after revealed text. |
| `className` | `string` | — | Optional className passed to the span. |
| `style` | `CSSProperties` | — | Optional style overrides merged last (e.g. vertical alignment offsets). |

## Use when
- Placing a blinking insertion cursor beside a text node or at the end of a typed string.
- Composing inside a custom typewriter or terminal scene where `typewriter` is too opinionated.
- Indicating an active input position before the `input` primitive's focus ring animation starts.

## Don't use when
- You need the full input UX (focus ring, border, value reveal) — use `input` instead, which owns its own caret.
- The typewriter effect is needed — use `typewriter`, which composes `caret` internally.
- You need a text selection highlight rather than an insertion point.