Theme for dashboardpage when nested within navbarpage

I created a R shiny app using dashboardpage but now I want to combine multiple dashboardpage app into a single app and was trying to using navbarpage to achieve this. It seems to work but adding navbarpage seems to completely change the style of the dashboardpage.

A minimum working example is below for a basic dashboardpage is below:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>library(shiny)
library(shinydashboard)
ui <-
dashboardPage(
dashboardHeader(title = "dash board header"),
dashboardSidebar(
sidebarMenu(
actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
menuItem("Averages", tabName = "Averages", icon = icon("list"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "uploadView",
fluidRow(
column(4,
fileInput("file1", "Choose CSV File 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
fileInput("file2", "Choose CSV file 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
hr(),
downloadButton("downloadData", "Download Data"),
checkboxGroupInput("SelectOption", label = "Select Box",
choices = c("Option 1", "Option 2"))
)
)
)
)
)
)
server <- function(input, output, session){ }
shinyApp(ui = ui, server = server)
</code>
<code>library(shiny) library(shinydashboard) ui <- dashboardPage( dashboardHeader(title = "dash board header"), dashboardSidebar( sidebarMenu( actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button menuItem("Data Upload", tabName = "uploadView", icon = icon("file")), menuItem("Averages", tabName = "Averages", icon = icon("list")) ) ), dashboardBody( tabItems( tabItem(tabName = "uploadView", fluidRow( column(4, fileInput("file1", "Choose CSV File 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), fileInput("file2", "Choose CSV file 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), hr(), downloadButton("downloadData", "Download Data"), checkboxGroupInput("SelectOption", label = "Select Box", choices = c("Option 1", "Option 2")) ) ) ) ) ) ) server <- function(input, output, session){ } shinyApp(ui = ui, server = server) </code>
library(shiny)
library(shinydashboard)

ui <- 
  dashboardPage(
  dashboardHeader(title = "dash board header"),
  dashboardSidebar(
    sidebarMenu(
      actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
      menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
      menuItem("Averages", tabName = "Averages", icon = icon("list"))
    )
  ),
  dashboardBody(
    tabItems(
      tabItem(tabName = "uploadView",
              fluidRow(
                column(4,
                       fileInput("file1", "Choose CSV File 1",
                                 accept = c("text/csv",
                                            "text/comma-separated-values,text/plain",
                                            ".csv")),
                       fileInput("file2", "Choose CSV file 1",
                                 accept = c("text/csv",
                                            "text/comma-separated-values,text/plain",
                                            ".csv")),
                       hr(),
                       downloadButton("downloadData", "Download Data"),
                       checkboxGroupInput("SelectOption", label = "Select Box", 
                                          choices = c("Option 1", "Option 2"))
                )
              )
      )
    )
  )
  )

server <- function(input, output, session){ }

shinyApp(ui = ui, server = server)

which gives:

However, when I try to put it within a navbarpage, the formatting changes. I.e.,

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ui <-
navbarPage(
"Test App",
tabPanel(
"Tab 1",
dashboardPage(
dashboardHeader(title = "dash board header"),
dashboardSidebar(
sidebarMenu(
actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
menuItem("Averages", tabName = "Averages", icon = icon("list"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "uploadView",
fluidRow(
column(4,
fileInput("file1", "Choose CSV File 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
fileInput("file2", "Choose CSV file 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
hr(),
downloadButton("downloadData", "Download Data"),
checkboxGroupInput("SelectOption", label = "Select Box",
choices = c("Option 1", "Option 2"))
)
)
)
)
)
)
),
tabPanel(
"Tab 2",
dashboardPage(
dashboardHeader(title = "dash board header 2"),
dashboardSidebar(disable = TRUE),
dashboardBody(tabItem(tabName = "Test"))
)
)
)
server <- function(input, output, session){ }
shinyApp(ui = ui, server = server)
</code>
<code>ui <- navbarPage( "Test App", tabPanel( "Tab 1", dashboardPage( dashboardHeader(title = "dash board header"), dashboardSidebar( sidebarMenu( actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button menuItem("Data Upload", tabName = "uploadView", icon = icon("file")), menuItem("Averages", tabName = "Averages", icon = icon("list")) ) ), dashboardBody( tabItems( tabItem(tabName = "uploadView", fluidRow( column(4, fileInput("file1", "Choose CSV File 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), fileInput("file2", "Choose CSV file 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), hr(), downloadButton("downloadData", "Download Data"), checkboxGroupInput("SelectOption", label = "Select Box", choices = c("Option 1", "Option 2")) ) ) ) ) ) ) ), tabPanel( "Tab 2", dashboardPage( dashboardHeader(title = "dash board header 2"), dashboardSidebar(disable = TRUE), dashboardBody(tabItem(tabName = "Test")) ) ) ) server <- function(input, output, session){ } shinyApp(ui = ui, server = server) </code>
ui <- 
  navbarPage(
    "Test App",
    tabPanel(
      "Tab 1",
      dashboardPage(
        dashboardHeader(title = "dash board header"),
        dashboardSidebar(
          sidebarMenu(
            actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
            menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
            menuItem("Averages", tabName = "Averages", icon = icon("list"))
          )
        ),
        dashboardBody(
          tabItems(
            tabItem(tabName = "uploadView",
                    fluidRow(
                      column(4,
                             fileInput("file1", "Choose CSV File 1",
                                       accept = c("text/csv",
                                                  "text/comma-separated-values,text/plain",
                                                  ".csv")),
                             fileInput("file2", "Choose CSV file 1",
                                       accept = c("text/csv",
                                                  "text/comma-separated-values,text/plain",
                                                  ".csv")),
                             hr(),
                             downloadButton("downloadData", "Download Data"),
                             checkboxGroupInput("SelectOption", label = "Select Box", 
                                                choices = c("Option 1", "Option 2"))
                      )
                    )
            )
          )
        )
      )
      ),
      tabPanel(
        "Tab 2",
        dashboardPage(
          dashboardHeader(title = "dash board header 2"),
          dashboardSidebar(disable = TRUE),
          dashboardBody(tabItem(tabName = "Test"))
        )
      )
  )


server <- function(input, output, session){ }

shinyApp(ui = ui, server = server)

which gives:

Is there a way to change the formatting of the dashboard component to get back to the way it was in the original picture. I’m not sure if I am trying to do use shinydashboard and navbarpage in a way they weren’t designed for. Suggestions for others of doing this would be welcome.

2

Update

I added a second example of how you can do this at the bottom.



If you want tabs-style navigation & keep dashboard, you could build the navigation.

You have to pay VERY close attention to what things are called and use a unique id where that’s an option. Everything needs to have unique names on the different dashboards. In my example code, there is already an error. I used the dashboard from your question as the first tab. Anytime any button is pressed, it thinks that the download data button is pressed. (e.g., the refresh button, the tabs, and any others among your pages)

Below is a working example of manual tabbing between dashboards.

I created two dashboards saved in objects db1 and db2. db1 is your initial dashboard.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>db1 <- dashboardPage(
dashboardHeader(title = "dash board header"),
dashboardSidebar(
sidebarMenu(
actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
menuItem("Averages", tabName = "Averages", icon = icon("list"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "uploadView",
fluidRow(
column(4,
fileInput("file1", "Choose CSV File 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
fileInput("file2", "Choose CSV file 1",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
hr(),
downloadButton("downloadData", "Download Data"),
checkboxGroupInput("SelectOption", label = "Select Box",
choices = c("Option 1", "Option 2"))
)
)
)
)
)
)
db2 <- dashboardPage(
dashboardHeader(title = "dash board header 2"),
dashboardSidebar(
sidebarMenu(
tags$div("not much to see here")
)
),
dashboardBody(
tags$div("Nothing to see here")
)
)
</code>
<code>db1 <- dashboardPage( dashboardHeader(title = "dash board header"), dashboardSidebar( sidebarMenu( actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button menuItem("Data Upload", tabName = "uploadView", icon = icon("file")), menuItem("Averages", tabName = "Averages", icon = icon("list")) ) ), dashboardBody( tabItems( tabItem(tabName = "uploadView", fluidRow( column(4, fileInput("file1", "Choose CSV File 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), fileInput("file2", "Choose CSV file 1", accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")), hr(), downloadButton("downloadData", "Download Data"), checkboxGroupInput("SelectOption", label = "Select Box", choices = c("Option 1", "Option 2")) ) ) ) ) ) ) db2 <- dashboardPage( dashboardHeader(title = "dash board header 2"), dashboardSidebar( sidebarMenu( tags$div("not much to see here") ) ), dashboardBody( tags$div("Nothing to see here") ) ) </code>
db1 <- dashboardPage(
  dashboardHeader(title = "dash board header"),
  dashboardSidebar(
    sidebarMenu(
      actionButton("refreshBtn", "Refresh", icon = icon("refresh"), onclick = "refreshPage()"), # Refresh button
      menuItem("Data Upload", tabName = "uploadView", icon = icon("file")),
      menuItem("Averages", tabName = "Averages", icon = icon("list"))
    )
  ),
  dashboardBody(
    tabItems(
      tabItem(tabName = "uploadView",
              fluidRow(
                column(4,
                       fileInput("file1", "Choose CSV File 1",
                                 accept = c("text/csv",
                                            "text/comma-separated-values,text/plain",
                                            ".csv")),
                       fileInput("file2", "Choose CSV file 1",
                                 accept = c("text/csv",
                                            "text/comma-separated-values,text/plain",
                                            ".csv")),
                       hr(),
                       downloadButton("downloadData", "Download Data"),
                       checkboxGroupInput("SelectOption", label = "Select Box", 
                                          choices = c("Option 1", "Option 2"))
                )
              )
      )
    )
  )
)
db2 <- dashboardPage(
  dashboardHeader(title = "dash board header 2"),
  dashboardSidebar(
    sidebarMenu(
      tags$div("not much to see here")
    )
  ),
  dashboardBody(
    tags$div("Nothing to see here")
  )
)

Within the UI, I created the navigation bar, buttons for tab control and added the dashboards.

For each dashboard or tab

  • there’s a tags$button within tags$nav (the use of tags$nav is so that it inherits styles from your dashboard)
  • there’s a tags$div after tags$nav

Note that in the buttons the text highlighted

tags$button(onclick = HTML("gimmeTab('Dashboard 1')"),...

MUST match what’s assigned to id in the tags$div that holds the matching dashboard

tags$div(id = "Dashboard 1",...


Read through the comments in the code for more info and if you have any questions, let me know.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ui <-
fluidPage(
tags$head( # this removes a left and right margin
tags$style(HTML(
"body > div.container-fluid {
padding: 0;
margin: 0;
}"
)), # adds tabs' control
tags$script(HTML(
"function gimmeTab(chosenOne){
let i;
let x = document.getElementsByClassName('tabber');
for(i = 0; i < x.length; i++) {
x[i].style.display = 'none';
}
document.getElementById(chosenOne).style.display = 'block';
}"
))
),
tags$body( # 2 primary elements: navigation bar and that which it controls
tags$nav(class = "navbar navbar-static-top", role = "navigation",
# here a button for each dashboard; must have class = "navBtn"
# must have unique inner text: first is 'Dashboard 1'
tags$button(onclick = HTML("gimmeTab('Dashboard 1')"), "Dashboard 1", class = "navBtn"),
# unique text: 'Dashboard 2'
tags$button(onclick = "gimmeTab('Dashboard 2')", "Dashboard 2", class = "navBtn")
),
# for each unique dashboard
# a `tags$div` with class 'tabber'
# the tags span exactly as shown here
# id that matches button inner text EXACTLY
# content - the dashboard
tags$div(id = "Dashboard 1", class = "tabber",
tags$span(onclick = HTML("this.parentELement.style.display = 'none'")),
tags$h2("Dashboard 1"),
db1
),
tags$div(id = "Dashboard 2", class = "tabber",
tags$span(onclick = "this.parentELement.style.display = 'none'"),
tags$h2("Dashboard 2"),
db2
)
)
)
server <- function(input, output, session){ }
shinyApp(ui = ui, server = server)
</code>
<code>ui <- fluidPage( tags$head( # this removes a left and right margin tags$style(HTML( "body > div.container-fluid { padding: 0; margin: 0; }" )), # adds tabs' control tags$script(HTML( "function gimmeTab(chosenOne){ let i; let x = document.getElementsByClassName('tabber'); for(i = 0; i < x.length; i++) { x[i].style.display = 'none'; } document.getElementById(chosenOne).style.display = 'block'; }" )) ), tags$body( # 2 primary elements: navigation bar and that which it controls tags$nav(class = "navbar navbar-static-top", role = "navigation", # here a button for each dashboard; must have class = "navBtn" # must have unique inner text: first is 'Dashboard 1' tags$button(onclick = HTML("gimmeTab('Dashboard 1')"), "Dashboard 1", class = "navBtn"), # unique text: 'Dashboard 2' tags$button(onclick = "gimmeTab('Dashboard 2')", "Dashboard 2", class = "navBtn") ), # for each unique dashboard # a `tags$div` with class 'tabber' # the tags span exactly as shown here # id that matches button inner text EXACTLY # content - the dashboard tags$div(id = "Dashboard 1", class = "tabber", tags$span(onclick = HTML("this.parentELement.style.display = 'none'")), tags$h2("Dashboard 1"), db1 ), tags$div(id = "Dashboard 2", class = "tabber", tags$span(onclick = "this.parentELement.style.display = 'none'"), tags$h2("Dashboard 2"), db2 ) ) ) server <- function(input, output, session){ } shinyApp(ui = ui, server = server) </code>
ui <- 
  fluidPage(
    tags$head(     # this removes a left and right margin
      tags$style(HTML(    
        "body > div.container-fluid {
          padding: 0;
          margin: 0;
        }"
      )),          # adds tabs' control
      tags$script(HTML(      
        "function gimmeTab(chosenOne){
          let i;
          let x = document.getElementsByClassName('tabber');
          for(i = 0; i < x.length; i++) {
            x[i].style.display = 'none';
          }
          document.getElementById(chosenOne).style.display = 'block';
        }"
      ))
    ),
    tags$body(       # 2 primary elements: navigation bar and that which it controls
      tags$nav(class = "navbar navbar-static-top", role = "navigation",
               
                    # here a button for each dashboard; must have class = "navBtn" 
                            # must have unique inner text: first is 'Dashboard 1'
               tags$button(onclick = HTML("gimmeTab('Dashboard 1')"), "Dashboard 1", class = "navBtn"),
                            # unique text: 'Dashboard 2'
               tags$button(onclick = "gimmeTab('Dashboard 2')", "Dashboard 2", class = "navBtn")
      ),      
      # for each unique dashboard
            #  a `tags$div` with class 'tabber' 
            # the tags span exactly as shown here
            # id  that matches button inner text EXACTLY
            # content - the dashboard
      tags$div(id = "Dashboard 1", class = "tabber", 
               tags$span(onclick = HTML("this.parentELement.style.display = 'none'")),
               tags$h2("Dashboard 1"), 
               db1
      ),
      tags$div(id = "Dashboard 2", class = "tabber", 
               tags$span(onclick = "this.parentELement.style.display = 'none'"),
               tags$h2("Dashboard 2"), 
               db2
      )
    )
    
  )

server <- function(input, output, session){ }

shinyApp(ui = ui, server = server)



Based on some of your comments, I thought I would give you another example of how you could do this.

Instead of buttons, this uses HREF (which is what navbar uses). This relies heavily on navbar‘s coding under the surface without hijacking the styles you’re using in your dashboard. Please note the comments explaining what elements are doing what and the things you need to consider if or when you use it.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ui2 <-
fluidPage(
tags$head(
tags$style(
# in this call to tags$style
# the first chunk removes a left and right margin
# the second is the highlight color with mouse and selection
# the background color and (text) color what I picked (that I thought looked ok)
HTML(
"div.container-fluid {
padding: 0;
margin: 0;
}
.navbar-default .navbar-nav>.active>a,
.navbar-default .navbar-nav>.active>a:hover,
.navbar-default .navbar-nav>.active>a:focus{
background-color: #9EC6DE;
color: white;
}"
))
),
tags$body( # 2 primary elements: navigation bar and that which it controls
# navigation bar
tags$nav(class = "navbar navbar-default navbar-static-top container-fluid", role = "navigation",
style = htmltools::css(background.color = "#3c8dbc", color = "white"), # white text matching blue bg
tags$ul(class = "nav navbar-nav",
# this is the settings for the tabs: 1 for each dashboard; the HREF must match the ID in the next section (less the #)
# each dashboard needs it's own tags$li(tags$a...)
# in href = "#....." must match the id set in tags$div() with the dashboard
tags$li(class = 'active', # set as default tab
tags$a(href = "#dashboard-1", `data-toggle` = "tab", style = "color: white;", "Dashboard 1")),
# each of the remaining tabs are formatted like this (without the active designation)
tags$li(tags$a(href = "#dashboard-2", `data-toggle` = "tab", style = "color: white;", "Dashboard 2"))
)
),
# that which the navigation bar controls
tags$div(class = "container-fluid",
tags$div(class = "tab-content",
# this is where the dashboards are stored
# each dashboard needs its' own tags$div
# the 'active' tab above is the only div here with the class 'active'
# in id = "....." must match the href (less #) found in the tags$li()
# set as tab-pane and default tab with the class 'active'
tags$div(id = "dashboard-1", class = "tab-pane active",
db1
), # remaining NOT active tabs, one for each tags$li() above
tags$div(id = "dashboard-2", class = "tab-pane", db2)
)
)
)
)
server <- function(input, output, session){ }
shinyApp(ui = ui2, server = server)
</code>
<code>ui2 <- fluidPage( tags$head( tags$style( # in this call to tags$style # the first chunk removes a left and right margin # the second is the highlight color with mouse and selection # the background color and (text) color what I picked (that I thought looked ok) HTML( "div.container-fluid { padding: 0; margin: 0; } .navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:hover, .navbar-default .navbar-nav>.active>a:focus{ background-color: #9EC6DE; color: white; }" )) ), tags$body( # 2 primary elements: navigation bar and that which it controls # navigation bar tags$nav(class = "navbar navbar-default navbar-static-top container-fluid", role = "navigation", style = htmltools::css(background.color = "#3c8dbc", color = "white"), # white text matching blue bg tags$ul(class = "nav navbar-nav", # this is the settings for the tabs: 1 for each dashboard; the HREF must match the ID in the next section (less the #) # each dashboard needs it's own tags$li(tags$a...) # in href = "#....." must match the id set in tags$div() with the dashboard tags$li(class = 'active', # set as default tab tags$a(href = "#dashboard-1", `data-toggle` = "tab", style = "color: white;", "Dashboard 1")), # each of the remaining tabs are formatted like this (without the active designation) tags$li(tags$a(href = "#dashboard-2", `data-toggle` = "tab", style = "color: white;", "Dashboard 2")) ) ), # that which the navigation bar controls tags$div(class = "container-fluid", tags$div(class = "tab-content", # this is where the dashboards are stored # each dashboard needs its' own tags$div # the 'active' tab above is the only div here with the class 'active' # in id = "....." must match the href (less #) found in the tags$li() # set as tab-pane and default tab with the class 'active' tags$div(id = "dashboard-1", class = "tab-pane active", db1 ), # remaining NOT active tabs, one for each tags$li() above tags$div(id = "dashboard-2", class = "tab-pane", db2) ) ) ) ) server <- function(input, output, session){ } shinyApp(ui = ui2, server = server) </code>
ui2 <- 
  fluidPage(
    tags$head(    
      tags$style( 
               # in this call to tags$style
               # the first chunk removes a left and right margin
               # the second is the highlight color with mouse and selection
                  # the background color and (text) color what I picked (that I thought looked ok)
        HTML(     
          "div.container-fluid {
          padding: 0;
          margin: 0;
        }
        .navbar-default .navbar-nav>.active>a,
        .navbar-default .navbar-nav>.active>a:hover,
        .navbar-default .navbar-nav>.active>a:focus{
          background-color: #9EC6DE;
          color: white;
        }"
        )) 
    ),
    tags$body(       # 2 primary elements: navigation bar and that which it controls
      # navigation bar
      tags$nav(class = "navbar navbar-default navbar-static-top container-fluid", role = "navigation",
               style = htmltools::css(background.color = "#3c8dbc", color = "white"),        # white text matching blue bg
               tags$ul(class = "nav navbar-nav",
                       
                       # this is the settings for the tabs: 1 for each dashboard; the HREF must match the ID in the next section (less the #)
                            # each dashboard needs it's own tags$li(tags$a...)
                            # in href = "#....." must match the id set in tags$div() with the dashboard
                       tags$li(class = 'active',         # set as default tab
                               tags$a(href = "#dashboard-1", `data-toggle` = "tab", style = "color: white;", "Dashboard 1")),
                            # each of the remaining tabs are formatted like this (without the active designation)
                       tags$li(tags$a(href = "#dashboard-2", `data-toggle` = "tab", style = "color: white;", "Dashboard 2"))
               )
      ),  
      # that which the navigation bar controls
      tags$div(class = "container-fluid",
               tags$div(class = "tab-content",        
               # this is where the dashboards are stored 
               # each dashboard needs its' own tags$div
               # the 'active' tab above is the only div here with the class 'active'
               # in id = "....." must match the href (less #) found in the tags$li()
               
                            # set as tab-pane and default tab with the class 'active'
                        tags$div(id = "dashboard-1", class = "tab-pane active", 
                                 db1
                        ),  # remaining NOT active tabs, one for each tags$li() above
                        tags$div(id = "dashboard-2", class = "tab-pane", db2)  
               )
      )
    )
  )

server <- function(input, output, session){ }

shinyApp(ui = ui2, server = server)

Recognized by R Language Collective

6

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật