SecretInput¶
A secure input for sensitive values like API keys, passwords, and tokens. Values are never rendered in the DOM — they're masked with bullet characters and managed through a secure edit/reveal/copy workflow.
The input is read-only by default. Users click the edit (pencil) button to enter edit mode, and can optionally reveal the masked value or copy it to clipboard. Both show_toggle and show_copy are enabled by default.
Action buttons (left-to-right): Edit (pencil) enters edit mode, Copy (clipboard) copies value, Reveal (eye) toggles mask on/off.
Edit Mode¶
Clicking the edit button hides the masked input and replaces it with a resizable textarea — always empty (the current secret is never pre-filled). Confirm (✓) and cancel (✗) buttons appear overlaid at the top-right corner of the textarea.
- Confirm —
Ctrl+Enteror click ✓ — transmits the new value (base64-encoded) and restores the mask. - Cancel —
Escapeor click ✗ — discards the input and restores the previous mask.
Basic Usage¶
from pywry import SecretInput
api_key = SecretInput(
label="API Key",
event="auth:api_key",
placeholder="Enter API key",
)
Both show_toggle and show_copy default to True, so a basic SecretInput already has all three action buttons (edit, copy, reveal).
Disabling Action Buttons¶
# Only the edit button — no reveal or copy
SecretInput(
label="Password",
event="auth:password",
show_toggle=False, # Hide the reveal/eye button
show_copy=False, # Hide the copy button
)
With Custom Handler¶
For secrets stored in an external vault or environment variable:
import os
from pywry import SecretInput
def resolve_api_key(value, *, component_id, event, label=None, **metadata):
"""Custom handler for API key storage.
Parameters:
value: None to get the secret, str to set the secret
component_id: unique component ID
event: the event string
label: optional label text
"""
if value is None:
# Get mode - return the secret
return os.environ.get("MY_API_KEY", "")
# Set mode - store the secret
os.environ["MY_API_KEY"] = value
return value
SecretInput(
label="API Key",
event="config:api_key",
handler=resolve_api_key,
value_exists=bool(os.environ.get("MY_API_KEY")),
)
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
label |
str |
"" |
Display label |
event |
str |
"toolbar:input" |
Event name emitted on interaction |
value |
SecretStr |
"" |
The secret value (never rendered in DOM) |
placeholder |
str |
"" |
Placeholder text shown when empty |
show_toggle |
bool |
True |
Show the eye reveal/hide button |
show_copy |
bool |
True |
Show the copy-to-clipboard button |
debounce |
int |
300 |
Debounce delay in ms for input events |
handler |
callable |
None |
Custom secret storage handler |
value_exists |
bool |
None |
Flag indicating a value exists externally |
component_id |
str |
auto | Unique ID for state tracking |
description |
str |
"" |
Tooltip/hover text |
disabled |
bool |
False |
Disable interaction |
style |
str |
"" |
Optional inline CSS |
Events¶
Emits the event name with payload on edit (when user exits the textarea):
value— the new secret value, base64-encodedencoded— alwaystrue(value must be decoded on the Python side)
Additional events:
{event}:copy— emitted when the copy button is clicked:{"componentId": "secret-abc123"}
The backend responds on{event}:copy-responsewith the decrypted value.{event}:reveal— emitted when the show/hide toggle is clicked:{"componentId": "secret-abc123"}
The backend responds on{event}:reveal-responsewith the decrypted value.
Common Patterns¶
API Configuration¶
config_toolbar = Toolbar(
position="top",
items=[
SecretInput(
label="API Key",
event="config:api_key",
placeholder="sk-...",
),
SecretInput(
label="API Secret",
event="config:api_secret",
placeholder="Enter secret",
),
Button(label="Save", event="config:save", variant="primary"),
],
)
Token Display¶
For displaying generated tokens:
import secrets
from pywry import PyWry, Toolbar, SecretInput, Button
app = PyWry()
def on_generate_token(data, event_type, label):
token = secrets.token_urlsafe(32)
app.emit("toolbar:set-value", {
"componentId": "token-display",
"value": token
}, label)
app.emit("pywry:alert", {"message": "New token generated!", "type": "success"}, label)
app.show(
"<h1>Token Generator</h1>",
toolbars=[
Toolbar(position="top", items=[
SecretInput(
component_id="token-display",
label="Token",
event="token:value",
),
Button(label="Generate New", event="token:generate"),
])
],
callbacks={"token:generate": on_generate_token},
)
Login Form¶
login_modal = Modal(
component_id="login-modal",
title="Login",
items=[
TextInput(label="Username", event="login:username"),
SecretInput(
label="Password",
event="login:password",
show_copy=False, # Don't need copy for password entry
),
Button(label="Login", event="login:submit", variant="primary"),
],
)
Security Notes¶
Client-Side Only
SecretInput masks display only. For true security:
- Never log secret values
- Use HTTPS in production
- Store secrets server-side when possible
- Consider environment variables for sensitive configs
API Reference¶
For complete parameter documentation, see the SecretInput API Reference.