如何使 Shiny 应用程序符合 W3C 标准?
How can I make a Shiny app W3C compliant?
我已经编写并优化了一个 Shiny 应用程序,现在我正在努力与我工作的组织的 IT 部门在他们的服务器上发布它。
目前,根据 W3C validator.
,他们声称该应用程序不符合 W3C,这是事实
我试图解决但没有成功的错误是:
<form class="well" role="complementary">
元素“form”上属性“role”的错误值“complementary”。
<label class="control-label" id="foo-label" for="foo">
“label”元素的“for”属性的值必须是非隐藏表单控件的ID。
此类错误也可以在非常小的闪亮应用程序中看到,例如:
# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)
# Define UI for random distribution app ----
ui <- fluidPage(
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select the random distribution type ----
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
# Define server logic for random distribution app ----
server <- function(input, output) {
# Reactive expression to generate the requested distribution ----
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data ----
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
})
}
# Create Shiny app ----
shinyApp(ui, server)
第二个错误似乎只与 radiobuttons 有关,而第一个错误似乎影响所有 shiny apps到目前为止,我已经在网上找到并使用 W3C 验证器进行了测试。
为了完整起见,我还报告了由 shiny 应用程序在 reprex 中生成的 HTML 代码:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="application/shiny-singletons"></script>
<script type="application/html-dependencies">jquery[3.6.0];shiny-css[1.7.1];shiny-javascript[1.7.1];ionrangeslider-javascript[2.3.1];strftime[0.9.2];ionrangeslider-css[2.3.1];bootstrap[3.4.1]</script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.min.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<script src="shared/ionrangeslider/js/ion.rangeSlider.min.js"></script>
<script src="shared/strftime/strftime-min.js"></script>
<link href="shared/ionrangeslider/css/ion.rangeSlider.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="shared/bootstrap/accessibility/css/bootstrap-accessibility.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/accessibility/js/bootstrap-accessibility.min.js"></script> <title>Tabsets</title>
</head>
<body>
<div class="container-fluid">
<h2>Tabsets</h2>
<div class="row">
<div class="col-sm-4">
<form class="well" role="complementary">
<div id="dist" class="form-group shiny-input-radiogroup shiny-input-container" role="radiogroup" aria-labelledby="dist-label">
<label class="control-label" id="dist-label" for="dist">Distribution type:</label>
<div class="shiny-options-group">
<div class="radio">
<label>
<input type="radio" name="dist" value="norm" checked="checked"/>
<span>Normal</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="unif"/>
<span>Uniform</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="lnorm"/>
<span>Log-normal</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="exp"/>
<span>Exponential</span>
</label>
</div>
</div>
</div>
<br/>
<div class="form-group shiny-input-container">
<label class="control-label" id="n-label" for="n">Number of observations:</label>
<input class="js-range-slider" id="n" data-skin="shiny" data-min="1" data-max="1000" data-from="500" data-step="1" data-grid="true" data-grid-num="9.99" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-keyboard="true" data-data-type="number"/>
</div>
</form>
</div>
<div class="col-sm-8" role="main">
<div class="tabbable">
<ul class="nav nav-tabs" data-tabsetid="9747">
<li class="active">
<a href="#tab-9747-1" data-toggle="tab" data-bs-toggle="tab" data-value="Plot">Plot</a>
</li>
<li>
<a href="#tab-9747-2" data-toggle="tab" data-bs-toggle="tab" data-value="Summary">Summary</a>
</li>
<li>
<a href="#tab-9747-3" data-toggle="tab" data-bs-toggle="tab" data-value="Table">Table</a>
</li>
</ul>
<div class="tab-content" data-tabsetid="9747">
<div class="tab-pane active" data-value="Plot" id="tab-9747-1">
<div id="plot" class="shiny-plot-output" style="width:100%;height:400px;"></div>
</div>
<div class="tab-pane" data-value="Summary" id="tab-9747-2">
<pre class="shiny-text-output noplaceholder" id="summary"></pre>
</div>
<div class="tab-pane" data-value="Table" id="tab-9747-3">
<div id="table" class="shiny-html-output"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
你有什么建议吗?
谢谢!
此消息也发布在 RStudio Community:抱歉交叉发布。
以下仅处理您提到的第一个错误(由于@BenBolkers 的评论,这个错误非常清楚),但希望它能为您指出正确的工具。
我会使用 htmltools::tagQuery 进行必要的修改 - 请检查以下内容:
# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)
library(htmltools)
# Define UI for random distribution app ----
ui <- fluidPage(
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
{querySidebarPanel <- tagQuery(sidebarPanel(
# Input: Select the random distribution type ----
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
))
querySidebarPanel$find(".well")$removeAttrs("role")$addAttrs("role" = "none")$allTags()},
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
# Define server logic for random distribution app ----
server <- function(input, output) {
# Reactive expression to generate the requested distribution ----
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data ----
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
})
}
# Create Shiny app ----
shinyApp(ui, server)
另请参阅 related chapter 来自 “闪亮的杰出用户界面”。
我已经编写并优化了一个 Shiny 应用程序,现在我正在努力与我工作的组织的 IT 部门在他们的服务器上发布它。 目前,根据 W3C validator.
,他们声称该应用程序不符合 W3C,这是事实我试图解决但没有成功的错误是:
<form class="well" role="complementary">
元素“form”上属性“role”的错误值“complementary”。<label class="control-label" id="foo-label" for="foo">
“label”元素的“for”属性的值必须是非隐藏表单控件的ID。
此类错误也可以在非常小的闪亮应用程序中看到,例如:
# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)
# Define UI for random distribution app ----
ui <- fluidPage(
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select the random distribution type ----
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
# Define server logic for random distribution app ----
server <- function(input, output) {
# Reactive expression to generate the requested distribution ----
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data ----
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
})
}
# Create Shiny app ----
shinyApp(ui, server)
第二个错误似乎只与 radiobuttons 有关,而第一个错误似乎影响所有 shiny apps到目前为止,我已经在网上找到并使用 W3C 验证器进行了测试。 为了完整起见,我还报告了由 shiny 应用程序在 reprex 中生成的 HTML 代码:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="application/shiny-singletons"></script>
<script type="application/html-dependencies">jquery[3.6.0];shiny-css[1.7.1];shiny-javascript[1.7.1];ionrangeslider-javascript[2.3.1];strftime[0.9.2];ionrangeslider-css[2.3.1];bootstrap[3.4.1]</script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.min.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<script src="shared/ionrangeslider/js/ion.rangeSlider.min.js"></script>
<script src="shared/strftime/strftime-min.js"></script>
<link href="shared/ionrangeslider/css/ion.rangeSlider.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="shared/bootstrap/accessibility/css/bootstrap-accessibility.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/accessibility/js/bootstrap-accessibility.min.js"></script> <title>Tabsets</title>
</head>
<body>
<div class="container-fluid">
<h2>Tabsets</h2>
<div class="row">
<div class="col-sm-4">
<form class="well" role="complementary">
<div id="dist" class="form-group shiny-input-radiogroup shiny-input-container" role="radiogroup" aria-labelledby="dist-label">
<label class="control-label" id="dist-label" for="dist">Distribution type:</label>
<div class="shiny-options-group">
<div class="radio">
<label>
<input type="radio" name="dist" value="norm" checked="checked"/>
<span>Normal</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="unif"/>
<span>Uniform</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="lnorm"/>
<span>Log-normal</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dist" value="exp"/>
<span>Exponential</span>
</label>
</div>
</div>
</div>
<br/>
<div class="form-group shiny-input-container">
<label class="control-label" id="n-label" for="n">Number of observations:</label>
<input class="js-range-slider" id="n" data-skin="shiny" data-min="1" data-max="1000" data-from="500" data-step="1" data-grid="true" data-grid-num="9.99" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-keyboard="true" data-data-type="number"/>
</div>
</form>
</div>
<div class="col-sm-8" role="main">
<div class="tabbable">
<ul class="nav nav-tabs" data-tabsetid="9747">
<li class="active">
<a href="#tab-9747-1" data-toggle="tab" data-bs-toggle="tab" data-value="Plot">Plot</a>
</li>
<li>
<a href="#tab-9747-2" data-toggle="tab" data-bs-toggle="tab" data-value="Summary">Summary</a>
</li>
<li>
<a href="#tab-9747-3" data-toggle="tab" data-bs-toggle="tab" data-value="Table">Table</a>
</li>
</ul>
<div class="tab-content" data-tabsetid="9747">
<div class="tab-pane active" data-value="Plot" id="tab-9747-1">
<div id="plot" class="shiny-plot-output" style="width:100%;height:400px;"></div>
</div>
<div class="tab-pane" data-value="Summary" id="tab-9747-2">
<pre class="shiny-text-output noplaceholder" id="summary"></pre>
</div>
<div class="tab-pane" data-value="Table" id="tab-9747-3">
<div id="table" class="shiny-html-output"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
你有什么建议吗? 谢谢!
此消息也发布在 RStudio Community:抱歉交叉发布。
以下仅处理您提到的第一个错误(由于@BenBolkers 的评论,这个错误非常清楚),但希望它能为您指出正确的工具。
我会使用 htmltools::tagQuery 进行必要的修改 - 请检查以下内容:
# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)
library(htmltools)
# Define UI for random distribution app ----
ui <- fluidPage(
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
{querySidebarPanel <- tagQuery(sidebarPanel(
# Input: Select the random distribution type ----
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
))
querySidebarPanel$find(".well")$removeAttrs("role")$addAttrs("role" = "none")$allTags()},
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
# Define server logic for random distribution app ----
server <- function(input, output) {
# Reactive expression to generate the requested distribution ----
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data ----
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
})
}
# Create Shiny app ----
shinyApp(ui, server)
另请参阅 related chapter 来自 “闪亮的杰出用户界面”。