- Inicio
- Primitivas
- Input OTP
- Ejemplos
Input OTP
Ejemplo básico de input otp demostrando el comportamiento principal.
Ejemplos
import * as InputOtp from "@solidiom/input-otp"
;<InputOtp.Root>Contenido de Input OTP</InputOtp.Root>Ver código fuente
export function Root(props: InputOTPRootProps) {
let inputRef: HTMLInputElement | undefined
const inputId = createStableId("otp-input")
const [internalValue, setInternalValue] = createSignal(props.defaultValue ?? "")
const [isFocused, setIsFocused] = createSignal(false)
const value = () => {
if (props.value !== undefined) {
return props.value() ?? ""
}
return internalValue()
}
const activeIndex = () => {
const len = value().length
return Math.min(len, props.maxLength - 1)
}
const patternRegex = props.pattern ? new RegExp(props.pattern) : undefined
const setValue = (next: string) => {
const truncated = next.slice(0, props.maxLength)
// Validate each character
if (patternRegex) {
const valid = truncated.split("").every((ch) => patternRegex.test(ch))
if (!valid) return
}
if (props.value === undefined) {
setInternalValue(truncated)
}
props.onValueChange?.(truncated)
if (truncated.length === props.maxLength) {
props.onComplete?.(truncated)
}
}
const handleInput = (e: InputEvent) => {
const target = e.target as HTMLInputElement
setValue(target.value)
}
const handleKeyDown = (e: KeyboardEvent) => {
if (props.disabled) {
e.preventDefault()
return
}
// Allow navigation keys
if (
e.key === "Backspace" ||
e.key === "Delete" ||
e.key === "ArrowLeft" ||
e.key === "ArrowRight"
) {
return
}
}
const handlePaste = (e: ClipboardEvent) => {
e.preventDefault()
if (props.disabled) return
const pasted = e.clipboardData?.getData("text/plain") ?? ""
setValue(pasted)
}
const focus = () => {
inputRef?.focus()
}
return (
<InputOTPContext
value={{
value,
maxLength: props.maxLength,
activeIndex,
isFocused,
pattern: patternRegex,
disabled: props.disabled,
focus,
}}
>
<div
class={props.class}
style={props.style}
onClick={focus}
{...applySemanticAttrs({
scope: "input-otp",
part: "root",
disabled: props.disabled,
})}
>
{/* Hidden input drives the actual value */}
<input
ref={inputRef}
id={inputId}
type="text"
inputmode="numeric"
autocomplete="one-time-code"
maxlength={props.maxLength}
value={value()}
disabled={props.disabled}
onInput={handleInput}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
aria-label="One-time password"
style={{
position: "absolute",
width: "1px",
height: "1px",
padding: "0",
margin: "-1px",
overflow: "hidden",
clip: "rect(0, 0, 0, 0)",
"white-space": "nowrap",
"border-width": "0",
}}
/>
{props.children}
</div>
</InputOTPContext>
)
}