Sensitive input
PortedA secret, such as an API key, hidden as dots. The show button reveals it until focus leaves the field; the copy button copies it and screen readers hear "Copied". readOnly shows a secret the user may copy but not change. Native <input> attributes and ref pass through to the field.
import { SensitiveInput } from "@etched/monet/sensitive-input";
export function Preview() {
return <SensitiveInput aria-label="API key" defaultValue="et_live_5c27e0d4b8a91f" />;
}Installation
import { SensitiveInput } from "@etched/monet/sensitive-input";Examples
API key
The value shows as dots. The show button reveals it until focus leaves the field; the copy button copies it.
import { SensitiveInput } from "@etched/monet/sensitive-input";
export function ApiKey() {
return (
<div className="grid">
<SensitiveInput label="API key" defaultValue="et_live_5c27e0d4b8a91f" />
</div>
);
}Sizes
import { SensitiveInput } from "@etched/monet/sensitive-input";
export function Sizes() {
return (
<div className="grid">
<SensitiveInput size="sm" aria-label="Webhook secret (small)" defaultValue="whsec_7Hq2Lx9" />
<SensitiveInput aria-label="Webhook secret" defaultValue="whsec_7Hq2Lx9" />
</div>
);
}Controlled
value and onValueChange. The copy button shows only while there is a value.
Signs each webhook request.
import { useState } from "react";
import { Button } from "@etched/monet/button";
import { SensitiveInput } from "@etched/monet/sensitive-input";
export function Controlled() {
const [secret, setSecret] = useState("whsec_7Hq2Lx9");
return (
<div className="grid">
<SensitiveInput label="Signing secret" value={secret} onValueChange={setSecret} description="Signs each webhook request." />
<div className="row">
<Button size="sm" onClick={() => setSecret(`whsec_${Math.random().toString(36).slice(2, 10)}`)}>
Rotate
</Button>
<Button size="sm" variant="ghost" onClick={() => setSecret("")}>
Clear
</Button>
</div>
</div>
);
}States
readOnly shows a secret the user may copy but not change. A disabled field has no buttons.
Set by the lab. Rotate it on the bench page.
This key has expired.
import { SensitiveInput } from "@etched/monet/sensitive-input";
export function States() {
return (
<div className="grid">
<SensitiveInput label="Bench token" defaultValue="bt_9a1f3c" readOnly description="Set by the lab. Rotate it on the bench page." />
<SensitiveInput label="Access key" defaultValue="AKIA4EXAMPLE" error="This key has expired." />
<SensitiveInput label="Legacy token" defaultValue="lt_0000" disabled />
<SensitiveInput label="New secret" placeholder="Paste the secret" required={false} />
</div>
);
}Accessibility
Tabgoes from the field to the show button, then to the copy button.EnterorSpacepresses them.- A password field, named by
labeloraria-label. The show button is named "Show value" (revealLabel) and hasaria-pressed;copyLabelnames the copy button. - Screen readers hear "Copied" from the field's own polite live region. If the clipboard refuses, they hear the copy keys, such as "Press Ctrl+C to copy".
copiedLabelandcopyKeysLabeltranslate them. - The value hides again when focus leaves the field and its buttons. A disabled field has no buttons.
- When a page has more than one, set
copyLabelto name the secret, such as "Copy API key".
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | – | Visible label. Without one, give the control an aria-label. |
| labelTooltip | ReactNode | – | More about the field, behind an info button after the label. |
| labelTooltipLabel | string | "More information" | Names the info button. |
| description | ReactNode | – | Help text below the control. Hidden while an error shows. |
| error | FieldError | – | |
| onCopy | () => void | – | Called after each copy. |
| copyLabel | string | "Copy to clipboard" | Names the copy button. |
| copiedLabel | string | "Copied" | What screen readers hear after a copy. |
| copyKeysLabel | (keys: string) => string | "Press ⌘C to copy" | Shown when the clipboard fails, with this device's copy keys ("⌘C" or "Ctrl+C"). |
| value | string | – | |
| defaultValue | string | – | |
| onValueChange | (value: string) => void | – | Called with the new text on each change. |
| size | "sm" | "base" | "base" | |
| revealLabel | string | "Show value" | Names the show button. |
| className | string | – | Class on the field's frame, for layout. |