Components/SensitiveInput

SensitiveInput

A masked field for API keys and other secrets.

VerifiedSince 0.6.0

Usage

Basic

A valid, a rejected, and a read-only key.

Loading demo...

Best Practices

  • Use it for stored secrets the user may read back; use TxInput type="password" for a credential being entered and never re-read.
  • Add readonly to a key the host issued and the user can't edit; it stays revealable and copyable, and focus stays on the container.
  • Steer people to copy rather than reveal-and-select; listen to reveal where a credential surface needs an audit trail.
  • Pass error rather than status="error" so the state and the message can't drift apart.
  • Localize through labels: seven of its ten strings are only heard by screen readers.

API Reference

Props

NameTypeDefaultDescription
modelValuestring''The secret (controlled).
labelstring''Field label; also the masked container's accessible name.
placeholderstring''Native placeholder, visible only while empty.
size'xs' | 'sm' | 'md' | 'lg''md'Height, padding, radius, and icon size; md matches TxInput.
status'default' | 'error'—Explicit visual state; derived from error when unset.
descriptionstring''Helper text below the field; replaced by error.
errorstring''Validation message; when set, turns the field red and sets aria-invalid.
disabledbooleanfalseNo reveal, no copy, no edit.
readonlybooleanfalseBlocks editing but not revealing or copying.
requiredbooleanfalseMarks the label required.
copyablebooleantrueRenders the copy tab.
maskstring'••••••••'Glyphs drawn in place of the value; fixed, so the secret's length doesn't leak.
copiedDurationnumber2000How long the copy tab stays confirmed, in ms.
labelsPartial<SensitiveInputLabels>—Overrides every rendered string, merged over SENSITIVE_INPUT_DEFAULT_LABELS.

Events

EventPayloadDescription
update:modelValue(value: string)Fires when the value changes.
copy(value: string)Fires after the value reaches the clipboard.
copyError(error: unknown)Fires when the clipboard refuses the write.
reveal—Fires when the value becomes visible; worth auditing for credentials.
mask—Fires when the value goes back behind the mask.

Exposed Methods

MethodDescription
focus()Focuses the container while masked, otherwise the input.
blur()Blurs the input.
reveal()Reveals the value programmatically.
mask()Re-masks the value.
copy()Runs the copy path; returns a promise.

Three States

StateBehavior
MaskedThe default whenever there is a value. Shows the mask glyphs; the container becomes a role="button" that reveals on click, Enter, or Space. On hover or focus, the glyphs change to Click to reveal.
Revealedtype flips to text and focus moves into the input. Blur or Escape re-masks, and Escape returns focus to the container; focusing the eye or copy button is not a blur.
EmptyA plain input with no mask, no copy tab, and no role="button". The first typed character switches to revealed; a value arriving from outside lands masked.

Overview

  • Copying never reveals the value.
  • The masked container is a role="button" (it holds buttons, so it can't be a <button>) with its own tabindex, aria-label (<label>, masked.), and aria-describedby; while masked, the <input> is aria-hidden with tabindex="-1".
  • A role="status" aria-live="polite" region announces Value hidden and Copied to clipboard.
  • Clicking the <label> reveals instead of forwarding focus.
  • autocomplete="off" and data-1p-ignore / data-lpignore keep password-manager overlays off the field.
  • The only transition, the copy tab's opacity, is off under reduced motion.

Technologies

  • Copy tries navigator.clipboard.writeText first, then falls back to a hidden-textarea execCommand and removes that node in a finally, so a failed copy never leaves the secret in the DOM.
  • Source: packages/tuffex/packages/components/src/sensitive-input/.
  • Behavior modelled on Kumo's SensitiveInput.
查看源码
packages/tuffex/packages/components/src/sensitive-input/index.ts