Components · Technical infrastructure
SecretField
A masked secret with reveal and hide, optional copy, and a "set, not shown" state.
Shown once, with copy
Shown once. Store it somewhere safe before you leave this page.
import { Field, FieldDescription, FieldLabel, SecretField } from '@rookcom/monarch-react';
const narrow = { width: '100%', maxWidth: '28rem' } as const;
function NewKey() {
return (
<Field style={narrow}>
<FieldLabel>Signing secret</FieldLabel>
<SecretField label="Signing secret" defaultValue="whsec_9d2f7a61c0b84e3f" readOnly copyable />
<FieldDescription>
Shown once. Store it somewhere safe before you leave this page.
</FieldDescription>
</Field>
);
}
<NewKey />Usage examples
Set, not shown
import { useState } from 'react';
import { Field, FieldDescription, FieldLabel, SecretField } from '@rookcom/monarch-react';
const narrow = { width: '100%', maxWidth: '28rem' } as const;
function SavedToken() {
const [value, setValue] = useState('');
return (
<Field style={narrow}>
<FieldLabel>API token</FieldLabel>
<SecretField
label="API token"
isSet
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<FieldDescription>
{value ? 'The new token replaces the saved one when you save.' : 'Stored encrypted.'}
</FieldDescription>
</Field>
);
}
<SavedToken />Sizes, standalone
import { SecretField } from '@rookcom/monarch-react';
const narrow = { width: '100%', maxWidth: '28rem' } as const;
<div style={{ ...narrow, display: 'grid', gap: 'var(--mn-space-3)' }}>
<SecretField label="Bot token" size="sm" defaultValue="bot-4f1a9c" />
<SecretField label="Access key" size="lg" defaultValue="AKIA4EXAMPLE7Q" copyable />
</div>Purpose
Enters or shows a secret (API key, bot token, signing secret) masked by default, with a toggle to reveal it and an optional copy button. The "set, not shown" state covers secrets the server stores but never sends back.
Use when
- A settings form takes a credential for an integration.
- A newly created key is shown once and the user must copy it.
- The server holds a saved secret: show that one exists, and let the user replace it.
Avoid when
- The user signs in: sign-in belongs to the identity flow, not a settings field.
- The value is not sensitive: use CopyField or Input.
Design principles
- Masked until the user asks. Revealing is a deliberate, reversible toggle.
- Copy never needs reveal: the copy button copies the value while it stays masked.
- Honest about saved secrets: an
isSetfield is empty, says a value is saved, and offers nothing to reveal or copy, because the browser does not have it. - Kept out of password managers and autocorrect, so a token is never saved as a login or "corrected".
API reference
import { SecretField } from '@rookcom/monarch-react';| Export | Kind | Rendering | Root class |
|---|---|---|---|
SecretField | component | client | .mn-secret- |
Forwards its ref to the <input>. All Input props pass through except type, which the reveal state controls.
Works inside a Field: the FieldLabel names the input, and Field descriptions and errors merge with the isSet description.
Generated from the TypeScript declarations of packages/react/src/components/technical/secret-field.
Properties
value/onChange (controlled) or defaultValue (uncontrolled); copy uses the current text in both modes.
revealed/onRevealedChange (controlled) or defaultRevealed (uncontrolled).
SecretField
A masked secret (API key, token, signing secret) with reveal/hide and an optional copy button. Never prefilled by the browser or password managers. Supports the "set, not shown" state for secrets the server never returns.
| Prop | Type | Description |
|---|---|---|
label required | string | What the secret is ("API key", "Bot token"). Names the reveal and copy buttons ("Show API key") and, outside a Field, the text box. |
children | ReactNode | |
className | string | |
copyable | boolean | Show a copy button. It copies the current value without revealing it. Default false. |
defaultRevealed | boolean | Uncontrolled initial value of `revealed`. Default false. |
disabled | boolean | |
id | string | |
invalid | boolean | Marks the value invalid. Inside a Field, the Field's `invalid` is used. |
isSet | boolean | A value is saved on the server but is never sent back, so there is nothing to reveal or copy. The field stays empty, says the secret is set, and typing a new value replaces it; leaving it blank keeps the saved one. |
onCopy | ((text: string) => void) | Called with the copied text after a successful copy. |
onCopyError | ((error: Error) => void) | Called when copying fails. |
onRevealedChange | ((revealed: boolean) => void) | |
revealable | boolean | Show the reveal/hide toggle. Default true. |
revealed | boolean | Controlled: whether the secret is shown in plain text. |
setDescription | string | Screen reader description while `isSet`. Default "A value is saved and hidden. Leave blank to keep it." |
setPlaceholder | string | Placeholder while `isSet` and empty. Default "Saved. Enter a new value to replace it". |
size | ControlSize |
Variants
| Prop | Values | Description |
|---|---|---|
size | 'sm''md''lg' | Input size; the inner buttons scale with it. |
revealable | 'true''false' | Show the reveal toggle. Default true. |
copyable | 'true''false' | Show a copy button. Default false. |
States
| State | Exposed as | Behaviour |
|---|---|---|
| Masked | type="password" | Default. The toggle is aria-pressed="false". |
| Revealed | data-revealed, type="text", aria-pressed="true" | Plain text; the toggle shows the eye-off icon. |
| Set, not shown | data-set | Empty with the setPlaceholder; described as saved and hidden. Reveal and copy are disabled until the user types a replacement. |
| Empty | disabled on the inner buttons | Nothing to reveal or copy yet. |
| Invalid | aria-invalid | From Field or the invalid prop. |
| Disabled / read-only | disabled, readonly | Native input states. |
Interaction behaviour
- The eye button toggles between masked and plain text.
- The copy button copies the current value (typed or given) and confirms like CopyButton.
- With
isSet, leaving the field blank keeps the saved secret: the product sends nothing. Typing a value replaces it.
Keyboard support
| Keys | Action |
|---|---|
| Tab | Input, then the reveal toggle, then the copy button. |
| Enter / Space | On the toggle: reveal or hide. On the copy button: copy. |
Accessibility
- Role
- textbox (password), toggle button, button
- Accessible name
- Outside a Field,
labelis the input’saria-label; inside one, the FieldLabel. The toggle is "Show {label}" witharia-pressed, the copy button "Copy {label}".
- The toggle keeps one name and reports its state with
aria-pressed, as the WAI-ARIA toggle-button pattern requires. - The
isSetstate is inaria-describedby, not only the placeholder. - The copy result is announced by CopyButton’s live region.
- Inner buttons are at least 28px, above the WCAG 2.2 target-size minimum.
Responsive behaviour
- Full width of its container; the buttons sit inside the input’s end edge and the text is padded to clear them.
- Logical properties throughout, so the buttons move to the left in right-to-left layouts.
Theme support
- Built from Input and IconButton, so every theme and more-contrast mode applies.
- The value uses
--mn-font-mono; the placeholder stays in the sans font.
Do and don't
Do
- Use
isSetfor saved secrets and send a new value only when the user typed one. - Pair a one-time secret with
copyableand a description that says it will not be shown again. - Keep validation and storage in the product; SecretField only masks and copies.
Don't
- Do not prefill a saved secret into the field; the server should never return it.
- Do not reveal by default.
- Do not use it for sign-in passwords.
Related components
- CopyField: For values that are not secret.
- CopyButton: The copy button it uses.
- Input: The Input it renders.
- Field: Label, help and errors.
- Alert: For a prominent "copy it now" warning around a one-time secret.
Dependencies
| Kind | Depends on |
|---|---|
| npm packages | react |
| Monarch components | Button, CopyButton, Field, Input |
Testing coverage
- Masked by default; the toggle reveals and hides with a stable name and
aria-pressed. - Toggles from the keyboard.
- Controlled reveal and controlled value.
- Copies the current value without revealing it, in controlled and uncontrolled modes.
- "Set, not shown": empty, described, reveal and copy disabled until a new value is typed.
- Turns off autocomplete, spell-check and autocapitalise, and marks the input for password managers to ignore.
- Inside a Field: FieldLabel names it, descriptions merge, invalid applies.
- Forwards the ref to the input;
revealable={false}hides the toggle.
| Check | Covered |
|---|---|
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/secret-field |
Tests: packages/react/src/components/technical/secret-field