React PII Redaction Chip

Models trained on and prompted with real data will surface emails, numbers, and names, and showing them by default is a leak waiting to happen. This masks the value inline, reveals it only on a deliberate click, and fires a hook so the access can be logged.

The support ticket was opened by , reachable at or . The card on file ends .

Click a chip to reveal it — each reveal fires onReveal so access can be logged. Revealed this session: none

Installation

npx shadcn@latest add "https://kelvinui.com/registry/pii-redaction.json"

Props

PropTypeDescription
valuestringThe real value, held client-side
typePiiTypeemail, phone, ssn, name, card, custom
labelstringOverride the masked placeholder
onReveal() => voidFires on reveal — wire to your audit log

Masked by default, revealed on purpose

The chip shows a lock, a masked placeholder, and the kind of data it hides (email, card) — enough context to read the sentence without exposing the value. A click reveals it and swaps in a hide affordance; a second click masks it again. The point is that seeing sensitive data becomes a deliberate act rather than the default, which is what turns "the whole team can see every customer email in every transcript" into "someone chose to look, and we know who."

Built for the audit, not just the eye

onReveal fires the moment a value is unmasked, so the access can be recorded — because the question a privacy review asks is not "was it masked" but "who looked, and when." The real value is held on the client and rendered only on reveal; in a stricter setup you'd keep it off the client entirely and fetch it through an authorised endpoint on click, logging server-side. Either way the component's contract is the same: nothing sensitive is shown until someone asks, and asking leaves a trace.

New components every week

Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.