Secret Field

Shows an API key masked but recognisable, re-hides it on a timer or when the tab is hidden, and copies the real value instead of dots.

StopsMasked API key pasted as dots

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/secret-field.json

The files land in your project. They're yours to edit.

Usage

secret-field-usage.tsx
import { SecretField } from "@/components/ui/secret-field"

<SecretField label="Secret key" value="sk_live_51NcBollardUiExampleKey8f2a" />

What it catches

  • Live versus test keys from the prefix (sk_live_, pk_test_…)
  • Masked text copied by hand, replaced with the real value on the clipboard
  • Revealed keys left on screen, re-masked after autoHide (default 10 s)
  • Tab switches while revealed, re-masked on visibilitychange

Props

SecretField props
PropTypeDefault
value* (required)

The secret itself, e.g. an API key.

string—
label

Visible label.

string"API key"
revealable

Allow the user to reveal the full value.

booleantrue
revealed

Controlled reveal state.

boolean—
defaultRevealed

Initial reveal state when uncontrolled.

booleanfalse
onRevealedChange

Called when the value is revealed or re-masked.

(revealed: boolean) => void—
autoHide

Re-mask after this many ms. 0 disables. The value also re-masks when the tab is hidden.

number10_000
visibleTail

Trailing characters left visible while masked.

number4
revealLabel

Accessible names for the buttons and feedback.

string"Reveal"
hideLabel

Accessible label of the hide button.

string"Hide"
copyLabel

Accessible label of the copy button.

string"Copy"
copiedLabel

Announced after a successful copy.

string"Copied"
copyFailedLabel

Announced when copying fails.

string"Couldn't copy. Reveal and select it instead."
copiedMaskedLabel

Shown when someone copies the masked dots by hand and gets the real key instead.

string"Copied the full key, not the dots"
liveLabel

Pill text for live and test keys.

string"Live"
testLabel

Badge for a test-mode key.

string"Test"

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Visible <label> on a read-only input; masked state exposed via aria-description "Hidden"
  • Reveal is an aria-pressed toggle with aria-controls and a changing aria-label
  • Copy button has an aria-label; copy result announced in a polite live region

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Show full secrets only once at creation if you can, and support rotation and revocation server-side.

  • The full secret is still in the page's JavaScript and React props; masking is visual
  • Clipboard contents are outside its control once copied (clipboard managers, sync)
  • Prefix detection covers common formats only

What it stops

Masked API key pasted as dots

Also known as

api key · secret input · reveal · copy key · stripe key · developer settings · password field · token

Field type

Dependencies

Pairs well with