Kosmesis
Components

Input OTP

A one-time password input, wrapping Morphos's OtpField primitive.

Installation

npx kosmesis add input-otp
pnpm dlx kosmesis add input-otp
yarn dlx kosmesis add input-otp
bunx kosmesis add input-otp

Install the following dependencies:

npm install @morphos/inputs
pnpm add @morphos/inputs
yarn add @morphos/inputs
bun add @morphos/inputs

Copy and paste the following code into your project.

input-otp.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { OtpField as MorphosOtpField, type OtpFieldProps as MorphosOtpFieldProps  } from "@morphos/inputs";import { cn } from "@/lib/utils";export type InputOTPProps = MorphosOtpFieldProps;/** * Morphos's `OtpField` renders every cell itself (it owns per-cell focus/paste/backspace logic * internally) rather than exposing an `InputOTPSlot`-style compound API — so unlike shadcn/ui's * version there's no separate slot/group/separator composition, just one styled component. * Target individual cells with the `data-index` attribute Morphos sets on each `<input>`. */@Component()export class InputOTP extends StatelessComponent<InputOTPProps> {  render() {    const { class: cls, ...rest } = this.props;    return (      <MorphosOtpField        class={cn(          "flex items-center gap-2",          "[&_input]:size-9 [&_input]:rounded-md [&_input]:border [&_input]:border-input [&_input]:text-center [&_input]:text-sm [&_input]:shadow-xs [&_input]:outline-none",          "[&_input:focus-visible]:z-10 [&_input:focus-visible]:border-ring [&_input:focus-visible]:ring-[3px] [&_input:focus-visible]:ring-ring/50",          "[&_input:disabled]:cursor-not-allowed [&_input:disabled]:opacity-50",          cls,        )}        {...rest}      />    );  }}

Install the following dependencies:

npm install @morphos/inputs @praxisjs/css
pnpm add @morphos/inputs @praxisjs/css
yarn add @morphos/inputs @praxisjs/css
bun add @morphos/inputs @praxisjs/css

Copy and paste the following code into your project.

input-otp.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { OtpField as MorphosOtpField, type OtpFieldProps as MorphosOtpFieldProps  } from "@morphos/inputs";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class InputOtpStyles extends Stylesheet {  $root = this.css({ display: "flex", alignItems: "center", gap: "0.5rem" })    .on("& input", {      width: "2.25rem",      height: "2.25rem",      borderRadius: `calc(${t.radius} - 2px)`,      border: `1px solid ${t.input}`,      textAlign: "center",      fontSize: "0.875rem",      boxShadow: "0 1px 2px 0 rgb(0 0 0 / 0.05)",      outline: "none",    })    .on("& input:focus-visible", { zIndex: 10, borderColor: t.ring, boxShadow: `0 0 0 3px color-mix(in oklab, ${t.ring} 50%, transparent)` })    .on("& input:disabled", { cursor: "not-allowed", opacity: 0.5 });}export type InputOTPProps = MorphosOtpFieldProps;/** * Morphos's `OtpField` renders every cell itself (it owns per-cell focus/paste/backspace logic * internally) rather than exposing an `InputOTPSlot`-style compound API — so unlike shadcn/ui's * version there's no separate slot/group/separator composition, just one styled component. * Target individual cells with the `data-index` attribute Morphos sets on each `<input>`. */@Component()export class InputOTP extends StatelessComponent<InputOTPProps> {  @Styled(InputOtpStyles) $s!: InputOtpStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosOtpField class={cx(this.$s.$root, cls)} {...rest} />;  }}

Examples

Usage

import { InputOTP } from "@/components/ui/input-otp";

<InputOTP length={6} onComplete={(value) => console.log(value)} />

Morphos's OtpField renders every cell itself (owning per-cell focus/paste/backspace logic internally) rather than exposing an InputOTPSlot-style compound API like shadcn/ui's — so there's just one component here, not a slot/group/separator composition. Target individual cells with the data-index attribute Morphos sets on each <input> if you need per-cell styling beyond what's built in.

Props

Passes through to Morphos's OtpFieldlength, value/defaultValue, disabled, name, pattern, inputMode, onValueChange, onComplete.

On this page