design-shiny-ui
정보
이 스킬은 개발자가 bslib를 사용한 테마 적용과 layout_columns를 활용한 반응형 그리드로 현대적인 Shiny 앱 인터페이스를 설계하는 데 도움을 줍니다. 값 상자(value boxes), 카드(cards), 사용자 정의 CSS/SCSS 구현, 접근성, 브랜드 일관성 유지 등을 다룹니다. 새로운 Shiny UI를 처음부터 구축하거나 기존 fluidPage 앱을 반응형 및 접근성 있게 현대화할 때 활용하세요.
빠른 설치
Claude Code
추천npx 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-uiClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
name: design-shiny-ui description: > Diseñar interfaces de usuario de aplicaciones Shiny usando bslib para temas, layout_columns para cuadrículas responsivas, cajas de valor, tarjetas y CSS/SCSS personalizado. Cubre layouts de página, accesibilidad y coherencia de marca. Úsalo al construir una nueva UI de app Shiny desde cero, al modernizar una app existente de fluidPage a bslib, al aplicar temas de marca, al hacer una app Shiny responsiva en diferentes tamaños de pantalla, o al mejorar la accesibilidad de una aplicación Shiny. locale: es source_locale: en source_commit: 6f65f316 translator: claude-opus-4-6 translation_date: 2026-03-16 license: MIT allowed-tools: Read Write Edit Bash Grep Glob metadata: author: Philipp Thoss version: "1.0" domain: shiny complexity: intermediate language: R tags: shiny, bslib, ui, theming, layout, css, accessibility, responsive
Design Shiny UI
Diseñar interfaces de aplicaciones Shiny responsivas y accesibles usando temas bslib, primitivas de layout modernas y CSS personalizado.
Cuándo Usar
- Al construir una nueva UI de app Shiny desde cero
- Al modernizar una app Shiny existente de fluidPage a bslib
- Al aplicar temas de marca (colores, fuentes) a una app Shiny
- Al hacer una app Shiny responsiva en diferentes tamaños de pantalla
- Al mejorar la accesibilidad de una aplicación Shiny
Entradas
- Requerido: Propósito de la aplicación y audiencia objetivo
- Requerido: Tipo de layout (sidebar, navbar, fillable, dashboard)
- Opcional: Colores y fuentes de marca
- Opcional: Si usar CSS/SCSS personalizado (predeterminado: solo bslib)
- Opcional: Requisitos de accesibilidad (nivel WCAG)
Procedimiento
Paso 1: Elegir el Layout de Página
bslib proporciona varios constructores de página:
# Layout sidebar — el más común para apps de datos
ui <- page_sidebar(
title = "My App",
sidebar = sidebar("Controls here"),
"Main content here"
)
# Layout navbar — para apps de múltiples páginas
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"))
)
# Layout fillable — el contenido llena el espacio disponible
ui <- page_fillable(
card(
full_screen = TRUE,
plotOutput("plot")
)
)
# Layout dashboard — cuadrícula de cajas de valor y tarjetas
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"))
)
)
Esperado: El layout de página coincide con las necesidades de navegación y contenido de la aplicación.
En caso de fallo: Si el layout no se ve bien, verifica que estés usando page_sidebar() / page_navbar() (bslib) y no fluidPage() / navbarPage() (shiny base). Las versiones bslib tienen mejores valores predeterminados y soporte de temas.
Paso 2: Configurar el Tema bslib
my_theme <- bslib::bs_theme(
version = 5, # Bootstrap 5
bootswatch = "flatly", # Tema preestablecido opcional
bg = "#ffffff", # Color de fondo
fg = "#2c3e50", # Color de primer plano (texto)
primary = "#2c3e50", # Color primario de marca
secondary = "#95a5a6", # Color secundario
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",
# ...
)
Usa el editor de temas interactivo durante el desarrollo:
bslib::bs_theme_preview(my_theme)
Esperado: La app se renderiza con colores de marca, fuentes y componentes Bootstrap 5 coherentes.
En caso de fallo: Si las fuentes no cargan, verifica el acceso a internet (Google Fonts lo requiere) o cambia a fuentes del sistema: font_collection("system-ui", "-apple-system", "Segoe UI"). Si las variables del tema no se aplican, verifica que estés pasando theme a la función de página.
Paso 3: Construir el Layout con Tarjetas y Columnas
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")
),
# Fila KPI — sin relleno
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"
)
),
# Fila de contenido principal
layout_columns(
col_widths = c(8, 4),
card(
card_header("Distribution"),
full_screen = TRUE,
plotOutput("main_plot")
),
card(
card_header("Summary"),
tableOutput("summary_table")
)
)
)
Primitivas de layout clave:
layout_columns()— cuadrícula responsiva concol_widthscard()— contenedor de contenido con cabecera/pie opcionalvalue_box()— visualización de KPI con icono y temalayout_sidebar()— sidebar anidada dentro de tarjetasnavset_card_tab()— tarjetas con pestañas
Esperado: Layout de cuadrícula responsiva que se adapta al tamaño de pantalla.
En caso de fallo: Si las columnas se apilan inesperadamente en pantallas anchas, verifica que la suma de col_widths sea 12 (cuadrícula Bootstrap). Si las tarjetas se superponen, asegúrate de fill = FALSE en las filas sin relleno.
Paso 4: Añadir Elementos de UI Dinámicos
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
)
}
)
})
# Paneles condicionales (sin viaje de ida y vuelta al servidor)
# En UI:
# conditionalPanel(
# condition = "input.show_advanced == true",
# numericInput("alpha", "Alpha", 0.05)
# )
}
Esperado: Los elementos de UI se actualizan dinámicamente basándose en las selecciones del usuario y los datos.
En caso de fallo: Si la UI dinámica parpadea, usa conditionalPanel() (basado en CSS) en lugar de renderUI() donde sea posible. Si las entradas dinámicas pierden sus valores al volver a renderizar, añade session$sendInputMessage() para restaurar el estado.
Paso 5: Añadir CSS/SCSS Personalizado (Opcional)
Para estilos más allá de las variables del tema bslib:
# CSS en línea
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; }
"))),
# ...
)
# Archivo CSS externo (coloca en directorio www/)
ui <- page_sidebar(
theme = my_theme,
tags$head(tags$link(rel = "stylesheet", href = "custom.css")),
# ...
)
Para integración SCSS con bslib:
my_theme <- bslib::bs_theme(version = 5) |>
bslib::bs_add_rules(sass::sass_file("www/custom.scss"))
Esperado: Estilos personalizados aplicados sin romper los temas de bslib.
En caso de fallo: Si el CSS personalizado entra en conflicto con bslib, usa variables CSS de Bootstrap (var(--bs-primary)) en lugar de colores hardcodeados. Esto garantiza que los cambios de tema se propaguen a los estilos personalizados.
Paso 6: Garantizar la Accesibilidad
# Añadir etiquetas ARIA a las entradas
selectInput("category", "Category",
choices = c("A", "B", "C")
) |> tagAppendAttributes(`aria-describedby` = "category-help")
# Añadir texto alternativo a los gráficos
output$plot <- renderPlot({
plot(data(), main = "Distribution of Values")
}, alt = "Histogram showing the distribution of selected values")
# Asegurar suficiente contraste de color en el tema
my_theme <- bslib::bs_theme(
version = 5,
bg = "#ffffff", # Fondo blanco
fg = "#212529" # Texto oscuro — ratio de contraste 15.4:1
)
# Usar HTML semántico
tags$main(
role = "main",
tags$h1("Dashboard"),
tags$section(
`aria-label` = "Key Performance Indicators",
layout_columns(
# cajas de valor...
)
)
)
Esperado: La app cumple los estándares WCAG 2.1 AA para contraste de color, navegación por teclado y compatibilidad con lectores de pantalla.
En caso de fallo: Prueba con la auditoría de accesibilidad de las herramientas de desarrollo del navegador (Lighthouse). Verifica los ratios de contraste de color con el verificador de contraste de WebAIM. Asegúrate de que todos los elementos interactivos sean accesibles por teclado.
Validación
- El layout de página se renderiza correctamente en anchos de escritorio y móvil
- El tema bslib se aplica consistentemente a todos los componentes
- Las cajas de valor se muestran con los temas e iconos correctos
- Las tarjetas se redimensionan correctamente en la cuadrícula responsiva
- El CSS personalizado usa variables de Bootstrap, no valores hardcodeados
- Todos los gráficos tienen texto alternativo para lectores de pantalla
- El contraste de color cumple WCAG AA (4.5:1 para texto)
- Los elementos interactivos son accesibles por teclado
Errores Comunes
- Mezclar UI de Shiny antigua y nueva: No mezcles
fluidPage()con componentes bslib. Usa exclusivamentepage_sidebar(),page_navbar()opage_fillable(). - Colores hardcodeados en CSS: Usa
var(--bs-primary)en lugar de#2c3e50. Los colores hardcodeados se rompen cuando cambia el tema. fill = FALSEfaltante en filas sin relleno: Las filas de cajas de valor y filas de resumen normalmente no deben estirarse para llenar el espacio disponible. Establecefill = FALSE.- Google Fonts en entornos sin conexión: Si la app se despliega en una red aislada, usa fuentes del sistema o archivos de fuente auto-alojados en lugar de
font_google(). - Ignorar el móvil: Prueba con el modo responsivo del navegador.
layout_columnsse apila automáticamente en pantallas estrechas, pero el CSS personalizado puede no hacerlo.
Habilidades Relacionadas
scaffold-shiny-app— configuración inicial de la app incluyendo la configuración del temabuild-shiny-module— crear componentes UI modularesoptimize-shiny-performance— renderizado consciente del rendimientoreview-web-design— revisión de diseño visual para layout, tipografía y colorreview-ux-ui— revisión de usabilidad y accesibilidad
GitHub 저장소
연관 스킬
executing-plans
디자인executing-plans 스킬은 검토 체크포인트가 포함된 통제된 배치로 실행할 완전한 구현 계획이 있을 때 사용합니다. 이 스킬은 계획을 불러와 비판적으로 검토한 후, 소규모 배치(기본값 3개 작업)로 작업을 실행하면서 각 배치 사이에 진행 상황을 아키텍트 검토를 위해 보고합니다. 이를 통해 내재된 품질 관리 체크포인트를 갖춘 체계적인 구현이 보장됩니다.
requesting-code-review
디자인이 스킬은 코드 변경 사항을 요구 사항에 따라 분석하기 위해 코드 리뷰어 하위 에이전트를 호출합니다. 작업 완료 후, 주요 기능 구현 후, 또는 메인 브랜치에 병합하기 전에 사용해야 합니다. 이 리뷰는 현재 구현체와 원래 계획을 비교하여 문제를 조기에 발견하는 데 도움이 됩니다.
connect-mcp-server
디자인이 스킬은 개발자들이 HTTP, stdio 또는 SSE 전송 방식을 통해 MCP 서버를 Claude Code에 연결하는 포괄적인 가이드를 제공합니다. GitHub, Notion 및 사용자 정의 API와 같은 외부 서비스를 통합하기 위한 설치, 구성, 인증 및 보안을 다룹니다. MCP 통합 설정, 외부 도구 구성 또는 Claude의 모델 컨텍스트 프로토콜 작업 시 활용하세요.
web-cli-teleport
디자인이 스킬은 작업 분석을 기반으로 개발자가 Claude Code 웹 인터페이스와 CLI 인터페이스 중 선택할 수 있도록 돕고, 두 환경 간 원활한 세션 텔레포트를 가능하게 합니다. 웹, CLI 또는 모바일 환경 전환 시 세션 상태와 컨텍스트를 관리하여 워크플로를 최적화합니다. 다양한 단계에서 서로 다른 도구가 필요한 복잡한 프로젝트에 사용하세요.
