Appsilon / rhino

Build high quality, enterprise-grade Shiny apps at speed
https://appsilon.github.io/rhino
287 stars 24 forks source link

Unable to set lang attribute to <html> #312

Open ashbaldry opened 2 years ago

ashbaldry commented 2 years ago

Steps to reproduce

  1. Create new {rhino} application
  2. Add lang = "en" to bootstrapPage
  3. Run application
  4. Inspect HTML

What happened?

There is no lang="en" in the top level <html> tag. The accessibility issue is flagged in the diagnostics

image

Expected behavior

The attribute is available in the tag and the accessibility issue is no longer raised

Rhino diagnostics

Windows 10 x64 build 22000 R version 4.1.1 (2021-08-10) rhino: 1.1.0 node: v16.15.1 yarn: 1.22.18

Comments

In most {shiny} applications, it is stored in the lang attribute of the top level shiny tag list. Maybe this can be extracted in attach_head_tags?

kamilzyla commented 2 years ago

Thanks for your report @ashbaldry! Indeed as of now there is no clean way to set the lang attribute on the <html> tag in Rhino.

Workaround

The object passed as the UI to shinyApp() must be of class html_document as otherwise Shiny will wrap everything with its own HTML template, in particular it will use an <html> tag without any attributes. As of now, the only way to achieve this in Rhino is to add legacy_entrypoint: app_dir to your rhino.yml (read about it here). This will give you full control over your app entrypoint. You now have a couple of ways to proceed.

With shiny::htmlTemplate()

page <- function(...) {
  htmlTemplate(
    document_ = TRUE,
    text_ = '
      <!DOCTYPE html>
      <html lang="en">
        <head>{{ headContent() }}</head>
        {{ body }}
      </html>
    ',
    body = tags$body(...)
  )
}

shinyApp(
  ui = page("Hello!"),
  server = function(input, output) {}
)

Without shiny::htmlTemplate()

page <- function(...) {
  structure(
    list(
      HTML("<!DOCTYPE html>"),
      tags$html(
        lang = "en",
        HTML("<head><!-- HEAD_CONTENT --></head>"),
        tags$body(...)
      )
    ),
    class = "html_document"
  )
}

shinyApp(
  ui = page("Hello!"),
  server = function(input, output) {}
)

Next steps

Ability to set attributes on the <html> tag sounds like a useful feature and we will consider adding it. It shouldn't be technically difficult (solutions are outlined above), but we'll need to design a good API for that.

ashbaldry commented 2 years ago

Thanks @kamilzyla for the workaround, I never knew you could create HTML that way for shiny applications!