pywry-orientation
When to reach for PyWry MCP tools (native webview rendering, Plotly, TradingView, AgGrid, chat) instead of writing Flask/Streamlit/Dash/Electron code. Use at…
Style widgets using CSS variables, theme colors, and dynamic style updates.
$ npx -y skills add deeleeramone/PyWry --skill styling --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/stylingContext preview
The summary Claude sees to decide when to auto-load this skill.
Style widgets using CSS variables, theme colors, and dynamic style updates.
> Style widgets using CSS variables, theme colors, and dynamic style updates.
PyWry provides CSS variables that adapt to dark/light themes. **Use these instead of hardcoded colors!**
var(--text-primary) /* Main text - high contrast */ var(--text-secondary) /* Muted text - medium contrast */ var(--text-muted) /* Very subtle text - low contrast */
var(--bg-primary) /* Main background (page/window) */ var(--bg-secondary) /* Card/section background */ var(--bg-tertiary) /* Nested elements, insets */ var(--bg-hover) /* Hover states */
var(--border-color) /* Standard borders */ var(--border-subtle) /* Subtle dividers */
var(--accent-color) /* Primary accent (brand color) */ var(--accent-hover) /* Accent hover state */
var(--success-color) /* Green - positive, success */ var(--warning-color) /* Orange/Yellow - caution */ var(--error-color) /* Red - error, danger */ var(--info-color) /* Blue - informational */
content = Div(
content="Status: OK",
component_id="status",
style="color: var(--success-color); background: var(--bg-secondary); padding: 10px;",
)html = """
<div style="
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 16px;
">
<h2 style="color: var(--text-primary); margin: 0;">Title</h2>
<p style="color: var(--text-secondary);">Description</p>
</div>
"""inject_css(widget_id, css="""
.custom-card {
background: var(--bg-secondary);
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.custom-card .title {
color: var(--text-primary);
font-weight: 600;
}
.custom-card .subtitle {
color: var(--text-muted);
font-size: 0.875rem;
}
""", id="custom-styles")# Update styles on an element by component_id
set_style(widget_id, component_id="status", styles={
"color": "var(--error-color)",
"backgroundColor": "var(--bg-tertiary)",
"borderLeft": "4px solid var(--error-color)",
})
# Update by selector
set_style(widget_id, selector=".price.up", styles={
"color": "var(--success-color)",
})
set_style(widget_id, selector=".price.down", styles={
"color": "var(--error-color)",
})Both camelCase and kebab-case work:
# camelCase (JavaScript style)
set_style(widget_id, component_id="box", styles={
"backgroundColor": "red",
"fontSize": "16px",
"borderRadius": "8px",
})
# kebab-case (CSS style)
set_style(widget_id, component_id="box", styles={
"background-color": "red",
"font-size": "16px",
"border-radius": "8px",
})# Switch to dark theme update_theme(widget_id, theme="dark") # Switch to light theme update_theme(widget_id, theme="light") # Follow OS preference (recommended) update_theme(widget_id, theme="system")
# Let the widget follow system preference update_theme(widget_id, theme="system") # The CSS variables automatically update when theme changes # Your content adapts without code changes
inject_css(widget_id, css="""
/* Custom component styles */
.my-button {
background: var(--accent-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
.my-button:hover {
background: var(--accent-hover);
}
/* Status indicators */
.status-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 500;
}
.status-badge.success {
background: var(--success-color);
color: white;
}
.status-badge.error {
background: var(--error-color);
color: white;
}
""", id="custom-styles") # ID lets you remove/replace later# Remove previously injected styles remove_css(widget_id, id="custom-styles")
# Inject with same ID replaces previous inject_css(widget_id, css="...", id="custom-styles") # Replaces previous
Button(label="Primary", variant="primary") # Accent color background Button(label="Default", variant="default") # Neutral background Button(label="Ghost", variant="ghost") # Transparent, border only Button(label="Danger", variant="danger") # Red/error color
Div(
content="Card content",
component_id="my-card",
style="padding: 20px; border-radius: 8px; background: var(--bg-secondary);",
class_name="my-card", # For CSS targeting
)# Most components accept style and class_name
Select(
label="Choose",
options=[...],
style="width: 200px;",
class_name="compact-select",
)inject_css(widget_id, css="""
/* Mobile-first base styles */
.dashboard {
display: flex;
flex-direction: column;
gap: 16px;
}
/* Tablet and up */
@media (min-width: 600px) {
.dashboard {
flex-direction: row;
}
.sidebar {
width: 250px;
flex-shrink: 0;
}
.main-content {
flex-grow: 1;
}
}
/* Desktop */
@media (min-width: 1PyWry is a cross-platform app factory, rendering engine and UI toolkit for Python that produces native desktop, web, and notebook experiences from a single API.
Repo: deeleeramone/PyWry
When to reach for PyWry MCP tools (native webview rendering, Plotly, TradingView, AgGrid, chat) instead of writing Flask/Streamlit/Dash/Electron code. Use at…
Add OAuth2 authentication to PyWry apps — Google, GitHub, Microsoft, or any OIDC provider.
Autonomous PyWry application building using LLM sampling, elicitation, and progress reporting.
How an agent operates inside a PyWry chat widget — reading user messages, attachments, @-context, tool-call result cards, edit/resend, settings changes.
**STOP. THIS IS THE AUTHORITATIVE REFERENCE FOR ALL COMPONENTS.** **YOU MUST USE THE EXACT EVENT SIGNATURES DOCUMENTED HERE.** **THERE ARE NO EXCEPTIONS. NO…