A value shown without being readable over a shoulder: an API key, a token, a signing secret. Hidden, it keeps its last few characters legible, since that tail is how one key is told from another; copy works whether or not it is revealed, and revealing fires a callback for panels that keep a log of it.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-secretNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorSecret } from "@/components/beste/component/inspector-secret";
// Issued elsewhere: shown and copied, not typed
<InspectorSecret label="API key" value={key} />
<InspectorSecret
label="Webhook secret"
value={secret}
visibleSuffix={6} // characters left legible while hidden
onReveal={() => console.log("secret revealed")}
onCopy={() => console.log("secret copied")}
revealable // on by default
copyable // on by default
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>
// Typed by the reader: the field is a real password input while it is hidden
<InspectorSecret
label="SMTP password"
editable
value={password}
onValueChange={setPassword}
onValueCommit={(next) => console.log("saved", next.length, "characters")}
placeholder="Not set"
name="smtp-password"
/>Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorSecret } from "@/components/beste/component/inspector-secret";
<InspectorSecret
label="API key"
className="w-72"
defaultValue="sk_test_EXAMPLE_NOT_A_REAL_KEY"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Enter | Commit an edit, while editable |
|---|---|
| Reveal | Shows the whole value and fires onReveal once |
| Copy | Copies the real value, revealed or not |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Label rendered on the left, inside the row. |
icon | LucideIcon | — | Optional leading icon shown before the label. |
value | string | — | Controlled value. Pair it with `onValueChange` when `editable`. |
defaultValue | string | — | Initial value in uncontrolled mode. |
onValueChange | (value: string) => void | — | Fires on every keystroke, and only exists while `editable`. |
onValueCommit | (value: string) => void | — | Fires once an edit is finished — the field left, or Enter pressed. |
editable | boolean | — | Let the secret be typed. Off by default: most of these are issued elsewhere and the row is there to show and copy one, not to invite an edit. |
revealable | boolean | true | Offer the reveal button. |
copyable | boolean | true | Offer the copy button. It copies the real value whether or not it is revealed, which is the point of having it. |
visibleSuffix | number | 4 | How many characters stay legible at the end while it is hidden. A key is recognised by its tail, and a row of dots that says nothing means opening the dashboard to find out which key this is. |
placeholder | string | — | Ghost text while there is no value. |
onReveal | () => void | — | Fires when the secret is revealed. A panel that keeps a log of who looked at what has to be told, and this is the only moment it happens. |
onCopy | (value: string) => void | — | Fires after a successful copy. |
disabled | boolean | — | Block interaction and dim the row. |
tone | "muted" | "outline" | "ghost" | "muted" | Surface treatment: filled (default), hairline outline, or bare until hover. |
size | "sm" | "default" | "lg" | "default" | Row height preset. |
name | string | — | Name of the field, so an editable secret can take part in a form. |
id | string | — | Id of the field, for an external `<label htmlFor>`. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |
Settings row that records a key combination: press it, press the keys, and the row keeps them as kbd chips printed in the platform's own glyphs. Mod stands for Cmd on a Mac and Ctrl everywhere else, so one stored value is right on both.
The line of prose that belongs between rows: what a setting is for, why one is switched off, what a value will cost. Four tones, each with its own mark, and the same text size as the rows around it.
The strip that splits a settings panel into two or three questions instead of one long scroll. It is the strip and nothing else: what the tabs switch between stays in the panel's own markup, beside the state that decides it. The pill slides between equal columns, arrow keys both move and select, and a tab can carry a count of what has changed under it.
A number and the unit that gives it meaning, in one row: px, rem, a percentage, or a keyword like auto that is the whole value on its own. Each unit may bring its own range, so a percentage stops at 100 while pixels do not.
A number with no ends, dragged from the row itself: for the values that have no maximum worth naming, like a z-index, an X offset or a letter-spacing. The drag is relative rather than positional, so pressing anywhere is safe, and a soft range gives the bar something to draw against that the value is free to leave. Only the reported number is quantized, so the pointer never fights the grid.