design-shiny-ui
Über
Diese Fähigkeit unterstützt Entwickler beim Erstellen und Modernisieren von Shiny-App-Oberflächen durch die Verwendung von bslib für das Theming, responsive Layouts mit `layout_columns` sowie Komponenten wie Value-Boxen und Karten. Sie behandelt das Anwenden von benutzerdefiniertem CSS/SCSS, die Gewährleistung von Barrierefreiheit und die Wahrung der Markenkonsistenz über alle Bildschirmgrößen hinweg. Nutzen Sie sie, wenn Sie eine neue App von Grund auf erstellen oder eine bestehende `fluidPage`-App auf ein modernes, responsives Design umstellen möchten.
Schnellinstallation
Claude Code
Empfohlennpx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/design-shiny-uiKopieren Sie diesen Befehl und fügen Sie ihn in Claude Code ein, um diese Fähigkeit zu installieren
Dokumentation
Design Shiny UI
Design responsive, accessible Shiny application interfaces using bslib theming, modern layout primitives, and custom CSS.
When to Use
- Building a new Shiny app UI from scratch
- Modernizing an existing Shiny app from fluidPage to bslib
- Applying brand theming (colors, fonts) to a Shiny app
- Making a Shiny app responsive across screen sizes
- Improving accessibility of a Shiny application
Inputs
- Required: Application purpose and target audience
- Required: Layout type (sidebar, navbar, fillable, dashboard)
- Optional: Brand colors and fonts
- Optional: Whether to use custom CSS/SCSS (default: bslib only)
- Optional: Accessibility requirements (WCAG level)
Procedure
Step 1: Choose the Page Layout
bslib provides several page constructors:
# Sidebar layout — most common for data apps
ui <- page_sidebar(
title = "My App",
sidebar = sidebar("Controls here"),
"Main content here"
)
# Navbar layout — for multi-page apps
ui <- page_navbar(
title = "My App",
nav_panel("Tab 1", "Content 1"),
nav_panel("Tab 2", "Content 2"),
nav_spacer(),
nav_item(actionButton("help", "Help"))
)
# Fillable layout — content fills available space
ui <- page_fillable(
card(
full_screen = TRUE,
plotOutput("plot")
)
)
# Dashboard layout — grid of value boxes and cards
ui <- page_sidebar(
title = "Dashboard",
sidebar = sidebar(open = "closed", "Filters"),
layout_columns(
fill = FALSE,
value_box("Revenue", "$1.2M", theme = "primary"),
value_box("Users", "4,521", theme = "success"),
value_box("Uptime", "99.9%", theme = "info")
),
layout_columns(
card(plotOutput("chart1")),
card(plotOutput("chart2"))
)
)
Got: Page layout matches the application's navigation and content needs.
If fail: If the layout doesn't look right, check that you're using page_sidebar() / page_navbar() (bslib) not fluidPage() / navbarPage() (base shiny). The bslib versions have better defaults and theming support.
Step 2: Configure the bslib Theme
my_theme <- bslib::bs_theme(
version = 5, # Bootstrap 5
bootswatch = "flatly", # Optional preset theme
bg = "#ffffff", # Background color
fg = "#2c3e50", # Foreground (text) color
primary = "#2c3e50", # Primary brand color
secondary = "#95a5a6", # Secondary color
success = "#18bc9c",
info = "#3498db",
warning = "#f39c12",
danger = "#e74c3c",
base_font = bslib::font_google("Source Sans Pro"),
heading_font = bslib::font_google("Source Sans Pro", wght = 600),
code_font = bslib::font_google("Fira Code"),
"navbar-bg" = "#2c3e50"
)
ui <- page_sidebar(
theme = my_theme,
title = "Themed App",
# ...
)
Use the interactive theme editor during development:
bslib::bs_theme_preview(my_theme)
Got: App renders with consistent brand colors, fonts, and Bootstrap 5 components.
If fail: If fonts don't load, check internet access (Google Fonts requires it) or switch to system fonts: font_collection("system-ui", "-apple-system", "Segoe UI"). If theme variables don't apply, check that you're passing theme to the page function.
Step 3: Build the Layout with Cards and Columns
ui <- page_sidebar(
theme = my_theme,
title = "Analysis Dashboard",
sidebar = sidebar(
width = 300,
title = "Filters",
selectInput("dataset", "Dataset", choices = c("iris", "mtcars")),
sliderInput("sample", "Sample %", 10, 100, 100, step = 10),
hr(),
actionButton("refresh", "Refresh", class = "btn-primary w-100")
),
# KPI row — non-filling
layout_columns(
fill = FALSE,
col_widths = c(4, 4, 4),
value_box(
title = "Observations",
value = textOutput("n_obs"),
showcase = bsicons::bs_icon("table"),
theme = "primary"
),
value_box(
title = "Variables",
value = textOutput("n_vars"),
showcase = bsicons::bs_icon("columns-gap"),
theme = "info"
),
value_box(
title = "Missing",
value = textOutput("n_missing"),
showcase = bsicons::bs_icon("exclamation-triangle"),
theme = "warning"
)
),
# Main content row
layout_columns(
col_widths = c(8, 4),
card(
card_header("Distribution"),
full_screen = TRUE,
plotOutput("main_plot")
),
card(
card_header("Summary"),
tableOutput("summary_table")
)
)
)
Key layout primitives:
layout_columns()— responsive grid withcol_widthscard()— content container with optional header/footervalue_box()— KPI display with icon and themelayout_sidebar()— nested sidebar within cardsnavset_card_tab()— tabbed cards
Got: Responsive grid layout that adapts to screen size.
If fail: If columns stack unexpectedly on wide screens, check col_widths sum equals 12 (Bootstrap grid). If cards overlap, ensure fill = FALSE on non-filling rows.
Step 4: Add Dynamic UI Elements
server <- function(input, output, session) {
output$dynamic_filters <- renderUI({
data <- current_data()
tagList(
selectInput("col", "Column", choices = names(data)),
if (is.numeric(data[[input$col]])) {
sliderInput("range", "Range",
min = min(data[[input$col]], na.rm = TRUE),
max = max(data[[input$col]], na.rm = TRUE),
value = range(data[[input$col]], na.rm = TRUE)
)
} else {
selectInput("values", "Values",
choices = unique(data[[input$col]]),
multiple = TRUE
)
}
)
})
# Conditional panels (no server round-trip)
# In UI:
# conditionalPanel(
# condition = "input.show_advanced == true",
# numericInput("alpha", "Alpha", 0.05)
# )
}
Got: UI elements update dynamically based on user selections and data.
If fail: If dynamic UI flickers, use conditionalPanel() (CSS-based) instead of renderUI() where possible. If dynamic inputs lose their values on re-render, add session$sendInputMessage() to restore state.
Step 5: Add Custom CSS/SCSS (Optional)
For styles beyond bslib theme variables:
# Inline CSS
ui <- page_sidebar(
theme = my_theme,
tags$head(tags$style(HTML("
.sidebar { border-right: 2px solid var(--bs-primary); }
.card-header { font-weight: 600; }
.value-box .value { font-size: 2.5rem; }
"))),
# ...
)
# External CSS file (place in www/ directory)
ui <- page_sidebar(
theme = my_theme,
tags$head(tags$link(rel = "stylesheet", href = "custom.css")),
# ...
)
For SCSS integration with bslib:
my_theme <- bslib::bs_theme(version = 5) |>
bslib::bs_add_rules(sass::sass_file("www/custom.scss"))
Got: Custom styles applied without breaking bslib theming.
If fail: If custom CSS conflicts with bslib, use Bootstrap CSS variables (var(--bs-primary)) instead of hardcoded colors. This ensures theme changes propagate to custom styles.
Step 6: Ensure Accessibility
# Add ARIA labels to inputs
selectInput("category", "Category",
choices = c("A", "B", "C")
) |> tagAppendAttributes(`aria-describedby` = "category-help")
# Add alt text to plots
output$plot <- renderPlot({
plot(data(), main = "Distribution of Values")
}, alt = "Histogram showing the distribution of selected values")
# Ensure sufficient color contrast in theme
my_theme <- bslib::bs_theme(
version = 5,
bg = "#ffffff", # White background
fg = "#212529" # Dark text — 15.4:1 contrast ratio
)
# Use semantic HTML
tags$main(
role = "main",
tags$h1("Dashboard"),
tags$section(
`aria-label` = "Key Performance Indicators",
layout_columns(
# value boxes...
)
)
)
Got: App meets WCAG 2.1 AA standards for color contrast, keyboard navigation, and screen reader compatibility.
If fail: Test with browser dev tools accessibility audit (Lighthouse). Check color contrast ratios with WebAIM's contrast checker. Ensure all interactive elements are keyboard-focusable.
Validation
- Page layout renders correctly on desktop and mobile widths
- bslib theme applies consistently to all components
- Value boxes display with correct themes and icons
- Cards resize properly in the responsive grid
- Custom CSS uses Bootstrap variables, not hardcoded values
- All plots have alt text for screen readers
- Color contrast meets WCAG AA (4.5:1 for text)
- Interactive elements are keyboard accessible
Pitfalls
- Mixing old and new Shiny UI: Don't mix
fluidPage()with bslib components. Usepage_sidebar(),page_navbar(), orpage_fillable()exclusively. - Hardcoded colors in CSS: Use
var(--bs-primary)instead of#2c3e50. Hardcoded colors break when the theme changes. - Missing
fill = FALSEon non-filling rows: Value box rows and summary rows usually shouldn't stretch to fill available space. Setfill = FALSE. - Google Fonts in offline environments: If the app deploys to an air-gapped network, use system fonts or self-hosted font files instead of
font_google(). - Ignoring mobile: Test with the browser responsive mode.
layout_columnsautomatically stacks on narrow screens, but custom CSS may not.
Related Skills
scaffold-shiny-app— initial app setup including theme configurationbuild-shiny-module— create modular UI componentsoptimize-shiny-performance— performance-conscious renderingreview-web-design— visual design review for layout, typography, and colourreview-ux-ui— usability and accessibility review
GitHub Repository
Verwandte Skills
content-collections
MetaDiese Skill bietet eine produktionsgetestete Einrichtung für Content Collections – ein TypeScript-first-Tool, das Markdown/MDX-Dateien in typsichere Datensammlungen mit Zod-Validierung umwandelt. Verwenden Sie ihn beim Erstellen von Blogs, Dokumentationsseiten oder inhaltsstarken Vite + React-Anwendungen, um Typsicherheit und automatische Inhaltsvalidierung zu gewährleisten. Er behandelt alles von der Vite-Plugin-Konfiguration und MDX-Kompilierung bis hin zur Deployment-Optimierung und Schema-Validierung.
polymarket
MetaDiese Fähigkeit ermöglicht es Entwicklern, Anwendungen mit der Polymarket-Prognosemärkte-Plattform zu erstellen, einschließlich API-Integration für Handel und Marktdaten. Sie bietet außerdem Echtzeit-Datenstreaming über WebSocket, um Live-Trades und Marktaktivitäten zu überwachen. Nutzen Sie sie zur Implementierung von Handelsstrategien oder zur Erstellung von Tools, die Live-Marktaktualisierungen verarbeiten.
creating-opencode-plugins
MetaDiese Fähigkeit unterstützt Entwickler dabei, OpenCode-Plugins zu erstellen, die in über 25 Ereignistypen wie Befehle, Dateien und LSP-Operationen eingreifen. Sie bietet die Plugin-Struktur, Event-API-Spezifikationen und Implementierungsmuster für JavaScript/TypeScript-Module. Nutzen Sie sie, wenn Sie den Lebenszyklus des OpenCode KI-Assistenten mit benutzerdefinierter ereignisgesteuerter Logik abfangen, überwachen oder erweitern müssen.
sglang
MetaSGLang ist ein hochperformantes LLM-Serving-Framework, das sich auf schnelle, strukturierte Generierung für JSON, Regex und agentenbasierte Workflows unter Verwendung seines RadixAttention-Prefix-Cachings spezialisiert. Es bietet deutlich schnellere Inferenz, insbesondere für Aufgaben mit wiederholten Präfixen, was es ideal für komplexe, strukturierte Ausgaben und Mehrfachdialoge macht. Wählen Sie SGLang gegenüber Alternativen wie vLLM, wenn Sie constrained decoding benötigen oder Anwendungen mit umfangreicher Präfix-Weitergabe entwickeln.
