Install
$ agentstack add skill-deeleeramone-pywry-modals ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Modals - MANDATORY PATTERN
> STOP. READ THIS ENTIRE FILE BEFORE CREATING MODALS.
Overview
Modals are reusable overlay dialogs that can contain any content - forms, confirmations, information panels, or custom HTML. They follow the same pattern as toolbars, passed to .show-* functions.
The ONLY Correct Way to Create Modals
Copy this EXACTLY. Do not deviate.
from pywry import Modal, show_plotly
fig = go.Figure(...)
widget = show_plotly(
fig,
modals=[
Modal(
component_id="settings-modal",
title="Settings",
items=["Configure your preferences here."],
size="medium",
)
],
toolbars=[{
"position": "top",
"items": [
{"type": "button", "label": "Open Settings", "event": "modal:open:settings-modal"}
]
}]
)
THAT'S IT. Button click opens the modal automatically.
Modal Schema
| Property | Type | Required | Default | Description | |----------|------|----------|---------|-------------| | component_id | str | YES | - | Unique identifier for the modal | | title | str | no | "" | Modal header title | | items | list[str] | no | [] | HTML content strings | | size | str | no | "medium" | "small", "medium", "large", "fullscreen" | | width | str | no | None | Custom width (e.g., "600px", "80%") | | max_height | str | no | None | Custom max-height (e.g., "400px") | | overlay_opacity | float | no | 0.5 | Backdrop opacity (0.0-1.0) | | close_on_escape | bool | no | True | Close when Escape key pressed | | close_on_overlay_click | bool | no | True | Close when clicking outside modal | | reset_on_close | bool | no | True | Reset form inputs when closed | | on_close_event | str | no | None | Event to emit when modal closes | | open_on_load | bool | no | False | Open modal immediately on page load | | style | str | no | "" | Additional CSS for this modal | | script | str | no | "" | Additional JavaScript for this modal | | class_name | str | no | "" | Additional CSS classes |
Size Presets
| Size | Width | Use Case | |------|-------|----------| | small | 320px | Confirmations, alerts | | medium | 500px | Forms, settings (default) | | large | 720px | Complex forms, tables | | fullscreen | 95vw / 95vh | Data grids, large content |
Modal Events
These are the ONLY events that work with modals:
Opening and Closing
| Event Type | Description | |------------|-------------| | modal:open: | Opens the modal | | modal:close: | Closes the modal | | modal:toggle: | Toggles open/closed state |
Example: Button to Open Modal
toolbars=[{
"position": "top",
"items": [
{"type": "button", "label": "Settings", "event": "modal:open:settings-modal"}
]
}]
Example: Button Inside Modal to Close
Modal(
component_id="confirm-modal",
title="Confirm Action",
items=[
"Are you sure?",
'Cancel',
'Confirm',
]
)
Built-in Close Behaviors
- X Button: Every modal has a close button in the top-right corner
- Escape Key: Press Escape to close (unless
close_on_escape=False) - Overlay Click: Click outside modal to close (unless
close_on_overlay_click=False)
resetonclose Behavior
When reset_on_close=True (default):
- All `
,,` elements are reset to their initial values - Form state is cleared when modal closes
- Next open shows fresh form
When reset_on_close=False:
- Form values persist between opens
- User can resume where they left off
JavaScript API
Access modal functions via window.pywry.modal:
// Open a modal
window.pywry.modal.open('my-modal');
// Close a modal
window.pywry.modal.close('my-modal');
// Toggle a modal
window.pywry.modal.toggle('my-modal');
// Check if modal is open
const isOpen = window.pywry.modal.isOpen('my-modal');
Complete Examples
1. Settings Modal with Form
from pywry import Modal, show_plotly
widget = show_plotly(
fig,
modals=[
Modal(
component_id="settings",
title="Chart Settings",
items=[
'',
' Title: ',
' Theme: ',
' Dark',
' Light',
' ',
' Apply',
'',
],
size="medium",
reset_on_close=False, # Keep form values
)
],
toolbars=[{
"position": "top",
"items": [
{"type": "button", "label": "⚙️ Settings", "event": "modal:open:settings"}
]
}]
)
2. Confirmation Dialog
Modal(
component_id="delete-confirm",
title="Delete Item",
items=[
'Are you sure you want to delete this item?',
'This action cannot be undone.',
'',
' Cancel',
' Delete',
'',
],
size="small",
close_on_overlay_click=False, # Force user to click a button
)
3. Modal with Custom Styling
Modal(
component_id="custom-modal",
title="Styled Modal",
items=["Custom styled content"],
style="""
#custom-modal .pywry-modal-container {
border: 2px solid var(--pywry-accent);
border-radius: 16px;
}
#custom-modal .pywry-modal-header {
background: linear-gradient(90deg, var(--pywry-accent), var(--pywry-bg-secondary));
}
""",
)
4. Modal with Custom JavaScript
Modal(
component_id="data-modal",
title="Data Preview",
items=[''],
script="""
// Populate data when modal opens
document.getElementById('data-modal').addEventListener('modal:opened', () => {
fetch('/api/data')
.then(r => r.json())
.then(data => {
document.getElementById('data-preview').textContent = JSON.stringify(data, null, 2);
});
});
""",
)
CSS Selectors for Styling
Target modal elements with these selectors:
| Selector | Element | |----------|---------| | # | The modal overlay | | # .pywry-modal-container | The modal box | | # .pywry-modal-header | Header with title and close button | | # .pywry-modal-title | Title text | | # .pywry-modal-close | X close button | | # .pywry-modal-body | Content area | | # .pywry-modal-footer | Footer area (if you add one) |
Theme Awareness
Modals automatically inherit the current theme:
.pywry-theme-dark→ Dark background, light text.pywry-theme-light→ Light background, dark text.pywry-theme-system→ Follows OS preference
Use CSS variables for consistent theming:
.pywry-modal-container {
background: var(--pywry-bg-secondary);
color: var(--pywry-text-primary);
border: 1px solid var(--pywry-border);
}
Common Mistakes
❌ Wrong: event: "open-modal" (missing modal: prefix and componentid) ❌ Wrong: event: "modal:open" (missing componentid) ❌ Wrong: Using onclick without window.pywry.modal. prefix
✅ Correct: event: "modal:open:my-modal" ✅ Correct: onclick="window.pywry.modal.close('my-modal')"
Dict Syntax (Alternative to Modal Class)
You can also use dict syntax if preferred:
modals=[
{
"component_id": "info-modal",
"title": "Information",
"items": ["Some info here"],
"size": "small",
}
]
Integration with Toolbars
Modals and toolbars work together seamlessly:
show_dataframe(
df,
toolbars=[{
"position": "top",
"items": [
{"type": "button", "label": "Export", "event": "grid:export-csv"},
{"type": "button", "label": "Filter", "event": "modal:open:filter-modal"},
{"type": "button", "label": "Help", "event": "modal:open:help-modal"},
]
}],
modals=[
Modal(component_id="filter-modal", title="Filters", items=["..."]),
Modal(component_id="help-modal", title="Help", items=["..."]),
]
)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: deeleeramone
- Source: deeleeramone/PyWry
- License: Apache-2.0
- Homepage: https://deeleeramone.github.io/PyWry/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.