deeleeramone/pywry/forms-and-inputs

Claude Code and agent skill by deeleeramone/pywry

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Install

npx vskill@latest install deeleeramone/pywry/forms-and-inputs

SKILL.md

Forms and User Input

Building interactive forms with validation and collecting user input.

Available Input Components

TypeComponentUse Case
textTextInputSingle-line text (names, emails)
textareaTextareaInputMulti-line text (comments, descriptions)
numberNumberInputNumeric values with min/max/step
dateDateInputDate selection
searchSearchInputSearch with debounce
secretSecretInputPasswords, API keys (value hidden)
selectSelectSingle choice dropdown
multiselectMultiSelectMultiple choices
radioRadioGroupVisible single choice (small set)
checkboxCheckboxBoolean toggle
toggleToggleOn/off switch
sliderSliderInputSingle value in range
rangeRangeInputTwo values (min/max range)

Basic Form Pattern

python
create_widget(
html='<div id="results">Fill out the form and click Submit</div>',
toolbars=[{
"position": "left",
"items": [
{"type": "text", "label": "Name", "event": "form:name", "placeholder": "Enter your name"},
{"type": "text", "label": "Email", "event": "form:email", "placeholder": "email@example.com"},
{"type": "number", "label": "Age", "event": "form:age", "min": 0, "max": 120, "value": 25},
{"type": "select", "label": "Country", "event": "form:country",
"options": [
{"label": "United States", "value": "us"},
{"label": "United Kingdom", "value": "uk"},
{"label": "Canada", "value": "ca"},
]},
{"type": "button", "label": "Submit", "event": "form:submit", "variant": "primary"},
]
}]
)

Collecting Form Data

From Events
python
events = get_events(widget_id, clear=True)
# Collect latest values
form_data = {}
for e in events:
if e["event_type"].startswith("form:"):
field = e["event_type"].replace("form:", "")
form_data[field] = e["data"].get("value")
# On submit
if "submit" in form_data:
process_form(form_data)
Tracking State
python
# Keep running state across event polls
form_state = {}
while True:
events = get_events(widget_id, clear=True)
for e in events:
if e["event_type"].startswith("form:"):
field = e["event_type"].replace("form:", "")
if field != "submit":
form_state[field] = e["data"].get("value")
else:
# Submit with current state
result = process_form(form_state)
set_content(widget_id, component_id="results", text=result)
time.sleep(0.1)

Validation Patterns

Show Error Toast
python
def validate_form(data):
if not data.get("name"):
show_toast(widget_id, message="Name is required", type="error")
return False
if not data.get("email") or "@" not in data["email"]:
show_toast(widget_id, message="Valid email is required", type="error")
return False
return True
Highlight Invalid Fields
python
def highlight_error(component_id):
set_style(widget_id, component_id=component_id, styles={
"borderColor": "var(--error-color)",
"boxShadow": "0 0 0 2px rgba(239, 68, 68, 0.2)",
})
def clear_error(component_id):
set_style(widget_id, component_id=component_id, styles={
"borderColor": "var(--border-color)",
"boxShadow": "none",
})
Show Inline Errors
python
# Create form with error placeholders
html = """
<div class="form-group">
<div id="name-error" class="error-message" style="display: none; color: var(--error-color);"></div>
</div>
"""
# Show error
set_content(widget_id, component_id="name-error", text="Name is required")
set_style(widget_id, component_id="name-error", styles={"display": "block"})
# Clear error
set_style(widget_id, component_id="name-error", styles={"display": "none"})

Input Component Details

Text Input
python
{"type": "text",
"label": "Username",
"event": "username",
"placeholder": "Enter username",
"value": "", # Default value
}
# Event data: {"value": "entered_text"}
Number Input
python
{"type": "number",
"label": "Quantity",
"event": "quantity",
"min": 1,
"max": 100,
"step": 1,
"value": 10,
}
# Event data: {"value": 10} # Always a number
Select
python
{"type": "select",
"label": "Category",
"event": "category",
"options": [
{"label": "Option A", "value": "a"},
{"label": "Option B", "value": "b"},
{"label": "Option C", "value": "c"},
],
"value": "a", # Default selection
}
# Event data: {"value": "a", "label": "Option A"}
MultiSelect
python
{"type": "multiselect",
"label": "Tags",
"event": "tags",
"options": [
{"label": "Important", "value": "important"},
{"label": "Urgent", "value": "urgent"},
{"label": "Review", "value": "review"},
],
"value": ["important"], # Default selections (array)
}
# Event data: {"value": ["important", "urgent"]}
Radio Group
python
{"type": "radio",
"label": "Priority",
"event": "priority",
"options": [
{"label": "Low", "value": "low"},
{"label": "Medium", "value": "medium"},
{"label": "High", "value": "high"},
],
"value": "medium",
}
# Event data: {"value": "medium"}
Toggle / Checkbox
python
{"type": "toggle", # or "checkbox"
"label": "Enable notifications",
"event": "notifications",
"value": True, # Default state
}
# Event data: {"value": true} # Boolean
Slider
python
{"type": "slider",
"label": "Volume",
"event": "volume",
"min": 0,
"max": 100,
"step": 5,
"value": 50,
}
# Event data: {"value": 50}
Range (Two Values)
python
{"type": "range",
"label": "Price Range",
"event": "price_range",
"min": 0,
"max": 1000,
"step": 10,
"value": [100, 500], # [min_value, max_value]
}
# Event data: {"value": [100, 500]}
Date
python
{"type": "date",
"label": "Start Date",
"event": "start_date",
"value": "2024-01-01", # ISO format
}
# Event data: {"value": "2024-01-15"}
Search (with debounce)
python
{"type": "search",
"label": "Search",
"event": "search",
"placeholder": "Type to search...",
"debounce": 300, # ms delay before firing event
}
# Event data: {"value": "search query"}

Secret Input (Passwords / API Keys)

python
{"type": "secret",
"label": "API Key",
"event": "api_key",
"placeholder": "Enter your API key",
}
# Events emitted:
# "api_key" - Value changed (value in event data, but NEVER rendered in HTML)
# "api_key:reveal" - User clicked reveal button
# "api_key:copy" - User clicked copy button
Handling Secret Events
python
events = get_events(widget_id, clear=True)
for e in events:
if e["event_type"] == "api_key":
# Store securely - never log or display
api_key = e["data"]["value"]
save_api_key_securely(api_key)
elif e["event_type"] == "api_key:reveal":
# User wants to see the key - show toast or handle appropriately
show_toast(widget_id, message="Key revealed in input", type="info")
elif e["event_type"] == "api_key:copy":
show_toast(widget_id, message="API key copied to clipboard", type="success")

Complete Form Example

python
from pywry import PyWry
from pywry.toolbar import Div, Button, Toolbar
app = PyWry()
content = Div(
content="""
<div style="padding: 20px;">
<h2>Registration Form</h2>
<div id="message" style="margin: 16px 0; padding: 12px; display: none;"></div>
</div>
""",
component_id="form-container",
)
widget = app.show(
html=content.build_html(),
height=500,
toolbars=[
Toolbar(
position="left",
items=[
{"type": "text", "label": "Full Name", "event": "form:name"},
{"type": "text", "label": "Email", "event": "form:email"},
{"type": "secret", "label": "Password", "event": "form:password"},
{"type": "select", "label": "Role", "event": "form:role", "options": [
{"label": "User", "value": "user"},
{"label": "Admin", "value": "admin"},
]},
{"type": "toggle", "label": "Accept Terms", "event": "form:terms"},
{"type": "button", "label": "Register", "event": "form:submit", "variant": "primary"},
]
)
]
)
# Handle form
form_state = {}
while True:
events = widget.get_events(clear=True)
for e in events:
if e["event_type"].startswith("form:"):
field = e["event_type"].replace("form:", "")
if field != "submit":
form_state[field] = e["data"].get("value")
else:
# Validate
if not form_state.get("name"):
widget.show_toast("Name is required", type="error")
elif not form_state.get("terms"):
widget.show_toast("Please accept terms", type="error")
else:
# Success
widget.set_content(
component_id="message",
html=f"<p style='color: var(--success-color);'>Welcome, {form_state['name']}!</p>"
)
widget.set_style(component_id="message", styles={"display": "block"})
time.sleep(0.1)

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
89
Repository forks
7
7-day trend score
22

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/deeleeramone/pywry/forms-and-inputs/badge)](https://verified-skill.com/skills/deeleeramone/pywry/forms-and-inputs)

Something wrong with this skill or its page? Tell us.