The culprit is actually not as.list but c.
Shiny UI functions do not return plain HTML as one could think, but a shiny.tag object (or shiny.tag.list list if several shiny.tag objects are grouped together).
A shiny.tag object is a list that contains information about the name of the HTML tag used and its children (e.g. other tags and its contents, for more information have a look here).
The reason we see the HTML code when a shiny.tag object is printed is because there are special print and as.character methods for shiny.tag and shiny.tag.list objects.
Have a look at the output of fluidRow(column(width = 12,"some content")):
str(fluidRow(column(width = 12,"some content")))
List of 3
$ name : chr "div"
$ attribs :List of 1
..$ class: chr "row"
$ children:List of 1
..$ :List of 3
.. ..$ name : chr "div"
.. ..$ attribs :List of 1
.. .. ..$ class: chr "col-sm-12"
.. ..$ children:List of 1
.. .. ..$ : chr "some content"
.. ..- attr(*, "class")= chr "shiny.tag"
- attr(*, "class")= chr "shiny.tag"
Internally it's a list! However, if printed it outputs:
print(fluidRow(column(width = 12,"some content")))
<div class="row">
<div class="col-sm-12">some content</div>
</div>
The same is true for titlePanel("A title"), it actually generates 2 shiny.tag objects in a shiny.tag.list:
str(titlePanel("A title"))
List of 2
$ :List of 3
..$ name : chr "head"
..$ attribs : Named list()
..$ children:List of 1
.. ..$ :List of 3
.. .. ..$ name : chr "title"
.. .. ..$ attribs : Named list()
.. .. ..$ children:List of 1
.. .. .. ..$ : chr "A title"
.. .. ..- attr(*, "class")= chr "shiny.tag"
..- attr(*, "class")= chr "shiny.tag"
$ :List of 3
..$ name : chr "h2"
..$ attribs : Named list()
..$ children:List of 1
.. ..$ : chr "A title"
..- attr(*, "class")= chr "shiny.tag"
- attr(*, "class")= chr [1:2] "shiny.tag.list" "list"
If you combine this as a list, the single shiny.tag objects still retain their list structure, so it's no problem for do.call(fluidPage, page_data_list) to generate the UI.
You basically create a list of lists:
page_data_list <- list(
titlePanel("A title"),
fluidRow(column(width = 12,"some content"))
)
str(page_data_list, max.level = 1)
List of 2
$ :List of 2
..- attr(*, "class")= chr [1:2] "shiny.tag.list" "list"
$ :List of 3
..- attr(*, "class")= chr "shiny.tag"
However, c tries to combine lists. The existing list objects don't get their own list in the newly created list, but the highest list levels get combined (c basically appends the lists):
page_data <- c(
titlePanel("A title"),
fluidRow(column(width = 12,"some content"))
)
str(page_data, max.level = 1)
List of 5
$ :List of 3
..- attr(*, "class")= chr "shiny.tag"
$ :List of 3
..- attr(*, "class")= chr "shiny.tag"
$ name : chr "div"
$ attribs :List of 1
$ children:List of 1
as.list(page_data) doesn't change anything because page_data is already a list.
Now the shiny.tag objects don't have the correct structure anymore and do.call(fluidPage, page_data) doesn't work.