feat(opal): stored-secret password tag, tab keyboard nav, tertiary actions
Description
1. Stored secrets in InputPasswordTypeIn
- New prop
existingValue: a stored value from the backend, already masked. - While
value === existingValue:- the field shows the value as a medium blue
Tagwith the key icon, and the input itself stays empty; - the reveal toggle is disabled;
- Backspace or Delete clears the value;
- typing or pasting replaces the value with the new text.
- the field shows the value as a medium blue
- After the first edit, the field is a normal password field again.
- To keep the stored secret on submit, the caller compares the submitted value with
existingValue. - The tag has no tooltip.
- An unchanged existing value does not block submission: the native
requiredcheck is off while the tag shows. AreadOnlyfield keeps its existing value, and the caller'sonKeyDownruns first and can cancel the deletion. - The
maskprop and its ✱ overlay are removed. Password fields always use the browser's own dots.
Callers that edit a stored secret now pass existingValue
- LLM provider modals (
APIKeyField, Bedrock, Ollama), SSO provider modal, index settings, web search, voice, tracing, image generation (OpenAI, Azure), OpenAPI OAuth client secret, MCP API token and OAuth secret, MCP user credentials, Craft app user credentials, Slack bot tokens. - In each one, the stored masked string is the field's initial value. So the untouched field keeps Formik's
dirtyfalse, and a Save gated ondirtystays blocked. Submit logic does not change: an unchanged value still counts as unchanged. - SSO used
isNonRevealableon edit only to protect the stored value. It usesexistingValuenow. - No change where the form starts empty for a stored secret: the hooks modal (only a placeholder holds the masked key), the Discord bot config and the custom-analytics key.
Raw password inputs move to InputPasswordTypeIn
- Slack bot tokens, reset password, impersonate (API key,
autoComplete="new-password"), custom analytics secret key, plugin connection dialog.
2. Keyboard and tab navigation (from the closed #16238)
These are the Opal parts of the closed Plugins PR. The plugins-specific parts are left out.
-
Tabs:- new
activationMode. In"manual", the default, arrows move focus and Enter or Space selects. - a focus ring shows while the keyboard moves focus;
- Tab enters the list on the selected tab and the next Tab leaves it, as the ARIA tabs pattern says;
- Escape leaves the tabs, but only from a tab: a control in
rightChildrenkeeps focus; - only a left click focuses a tab.
orientationis omitted from the props: Opal tabs are horizontal only.
- new
-
Interactive(stateless): keyboard focus shows the hover state in place of the browser's ring. -
useGridNavigation: keyboard focus on a control inside a grid item shows again. -
InputTypeInclear button: it keeps focus in the field after it clears the value, it has anaria-label, and it sendsonChangea real change event. -
Escape on a control beside a text field (the clear button, the reveal toggle, a chevron, a chip) returns focus to the field, also when a tooltip consumed the key. This covers
InputTypeInand every input built on it, plusTagField. OnInputTimeandInputDatePicker, which have no single input, it focuses the first segment.
3. Input action buttons
-
The right-side icon buttons use
tertiaryprominence: the clear buttons ofInputTypeIn,TagField,InputTimeandInputDatePicker, and the date picker's calendar button. -
The
InputTypeInandUploadControlclear buttons have tooltips. -
The tooltip-only clear and calendar buttons of
TagField,InputTimeandInputDatePickerget anaria-label, so they have an accessible name. -
The clear button is always an input's last control.
InputDatePickerdrew it before the calendar button, andTagField(InputTypeInTag, the multi-select) drew it before the dropdown chevron. -
TagField(InputTypeInTag, the multi-select) usessize="sm"for its clear button, as the other inputs do. It usedxs.
Additional Options
- [Optional] Please cherry-pick this PR to the latest release version.
- [Optional] Override Linear Check
Summary by cubic
Adds an existingValue prop to InputPasswordTypeIn so forms that edit backend secrets show the saved value as a key tag instead of editable masked text, and polishes Opal tab keyboard navigation, focus handling, and input action buttons.
Stored secrets
existingValuemarks a stored backend value: while the field's value equals it, the value renders as a key tag, the input stays empty, and the reveal toggle is disabled.- Backspace or Delete clears it; typing or pasting replaces it whole. A read-only field keeps the value, the caller's
onKeyDowncan cancel the deletion, and an unchanged tag doesn't fail a native required check. - Secret-editing forms (Slack tokens, SSO, MCP, language-model and image-gen modals, tracing, voice, web search, and more) now pass
existingValue; a few raw password inputs move toInputPasswordTypeIn. Themaskprop and idle asterisk overlay are removed. - E2E specs for OpenAPI OAuth, index settings, and web search now verify the stored value appears as a tag with an empty input.
Keyboard and input actions
Tabsdefaults to manual activation: arrows move focus, Enter or Space selects, a focus ring tracks keyboard movement, and Escape leaves the tabs. Only a plain left click focuses a tab; a caller'sonKeyDowncan cancel the Escape.- Keyboard focus on
Interactivesurfaces replaces the browser ring with the hover state;useGridNavigationnow shows focus on controls inside grid items. InputTypeIn's clear button sends a real change event, keeps focus in the field after clearing, and gains anaria-label.- Escape on an input's side controls (clear, reveal toggle, chevron, chip) returns focus to the field, even when a tooltip consumed the key; on
InputTimeandInputDatePickerit focuses the first segment. - Input action buttons use
tertiaryprominence, the clear button is always an input's last control, andTagField's clear button issmlike the other inputs'.
Summary by CodeRabbit
-
New Features
- Password fields display saved credentials as masked, non-revealable tags. Clear them with Backspace or Delete, or replace them by typing or pasting.
- Tabs use manual activation: arrow keys move focus, while Enter or Space selects.
-
Improvements
- Credential fields preserve saved values while editing across administrative and configuration forms.
- Clear controls provide localized labels and tooltips, and return focus to the field.
- Escape restores focus from date, time, tag, and input controls.
- Keyboard focus styling is more consistent across interactive controls and grid navigation.