R Shiny - Popup window when hovering over icon - r

I would like to simply add a hovering window over an icon after a simple line of text.
I have found the shinyBS package, which seems to make this possible but it is linked to shiny outputs.
Having something like the code below in the "ui" of the shiny app makes the buttons work but they are linked to the radioButtons in this case.
CVI <- c("Hello1", "Hello2", "Hello3")
CNI <- c("Peter1", "Peter2", "Peter3")
radioButtons(inputId = "Attribute", label="Attribute", choiceValues = CVI,
choiceNames = list(
tagList(
tags$span(CNI[1]), #DoS
tags$span(icon("info-circle"), id = "1_info", style = "color: gray;")
),
tagList(
tags$span(CNI[2]), #DoO
tags$span(icon("info-circle"), id = "2_info", style = "color: gray;")
),
tagList(
tags$span(CNI[3]), #Ratio
tags$span(icon("info-circle"), id = "3_info", style = "color: gray;")
))
),# radiobuttons end
Popover buttons
bsPopover(id="1_info", title=NULL, content="Test1", trigger="hover", placement="right", options=list(container="body")),
bsPopover(id="2_info", title=NULL, content="Test2", trigger="hover", placement="right", options=list(container="body")),
bsPopover(id="3_info", title=NULL, content="Test3", trigger="hover", placement="right", options=list(container="body"))
How can I achieve something similar but without the radioButtons, simply like the word "Example" and then an icon where I hover and get a popup with some information (see picture).
I would create it somewhat like this:
Example_Text <- "Example_text" # This is what comes in the popup
"Example", span(icon("info-circle"), id = "Example_Popup", style = "color: gray;")

The native HTML tooltips are not customizable. Bootstrap tooltips are.
library(shiny)
library(bslib)
css <- '
.tooltip {
pointer-events: none;
}
.tooltip > .tooltip-inner {
pointer-events: none;
background-color: #73AD21;
color: #FFFFFF;
border: 1px solid green;
padding: 10px;
font-size: 25px;
font-style: italic;
text-align: justify;
margin-left: 0;
max-width: 1000px;
}
.tooltip > .arrow::before {
border-right-color: #73AD21;
}
'
js <- "
$(function () {
$('[data-toggle=tooltip]').tooltip()
})
"
shinyApp(
server = function(input,output,session){},
ui = fluidPage(
theme = bs_theme(version = 4),
tags$head(
tags$style(HTML(css)),
tags$script(HTML(js))
),
br(),
span(
"Example",
span(
`data-toggle` = "tooltip", `data-placement` = "right",
title = "A tooltip",
icon("info-circle")
)
)
)
)

This can be done with div(title=, style=, ...).
shinyApp(
server = function(input,output,session){},
ui = fluidPage(
span(
"Example",
div(style = "display:inline-block;",
title = "A tooltip",
icon("info-circle")))
)
)
Pause your mouse over the icon and you'll see A tooltip. It isn't styled like the directional callout you have in your page, perhaps it's sufficient.

Related

header style not working when putting a button in the header of shinydashboard

I managed to put an action button in the shiny dashboard's header. However, when applying styling using tags$li, it only applies to the sidebar. When removing the tags$a portion, the styling gets applied throughout the header. Not sure how to fix it, so the styling is consistent across the header- was hoping to get some hint/directions in stack overflow.
I have seen these posts:
Home Button in Header in R shiny Dashboard
Login Button in shinydashboard dashboardHeader
This question is extension of my previous question: resizing an action button causes misalignment in the header in shinydashboard
Here is a reprex (with an image below):
library(shiny)
library(shinydashboard)
library(htmltools)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(
tags$li(class = "dropdown",
tags$a(actionButton(inputId = "email1", label = "",
icon = icon("envelope", lib = "font-awesome")
#Also tried to adjust the width and height of transparent, no luck
# ,
# style='height: 20px;
# background: transparent;
# border: none;
# font-size: 2rem;
# transform: translate(5%, -30%);'
),
href="mailto:have_a_nice_day#yep.com;"),
# has no effect on the main header bar (the header in which button is placed)
tags$style(".main-header {max-height: 20px}"),
tags$style(".main-header .logo {height: 20px;}"),
tags$style(".sidebar-toggle {height: 20px; padding-top: 1px !important;}"),
tags$style(".navbar {min-height:20px !important}")
)
),
dashboardSidebar(
),
dashboardBody()
)
server <- function(input, output){}
shinyApp(ui, server)
Thank you very much for your help!
Your code works fine if you don't have an email icon in the header. Try this
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
# tags$li(class = "dropdown",
# tags$a(actionButton(inputId = "email1", label = "",
# icon = icon("envelope", lib = "font-awesome")
#
# #Also tried to adjust the width and height of transparent, no luck
# # ,
# # style='height: 20px;
# # background: transparent;
# # border: none;
# # font-size: 2rem;
# # transform: translate(5%, -30%);'
#
# ),
# href="mailto:have_a_nice_day#yep.com;"),
# ),
tags$li(class = "dropdown",
# has effect on the main header bar
tags$style(".main-header {max-height: 20px !important;}"),
tags$style(".main-header .logo {height: 20px !important;}"),
tags$style(".sidebar-toggle {height: 20px; padding-top: 1px !important;}"),
tags$style(".navbar {min-height:20px !important}")
)
),
dashboardSidebar(
# Adjust the sidebar
tags$style(".left-side, .main-sidebar {padding-top: 20px}")
),
dashboardBody()
)
server <- function(input, output){}
shinyApp(ui, server)
That's because of the paddings of the button and the a tag. You can do:
tags$a(actionButton(inputId = "email1", label = "",
icon = icon("envelope", lib = "font-awesome"),
style = "padding-top: 0; padding-bottom: 0;"),
href="mailto:have_a_nice_day#yep.com;",
style = "padding-top: 0; padding-bottom: 0;")
If you don't use the action button, it is better to do:
library(fontawesome)
and
tags$li(class = "dropdown",
tags$a(fa("envelope"),
href="mailto:have_a_nice_day#yep.com;",
style = "padding-top: 0; padding-bottom: 0;"),

resizing an action button causes misalignment in the header in shinydashboard

I have placed an action button on the header of my shinydashboard that automatically opens the default mail application and fills the To: line. However, when I resize the button, the collapsible sidebar header and the main header get misaligned (please see the picture below for a reference).
Furthermore, I have checked out these posts in SO:
Aligning a text with variable length in the middle of dashboard header
Align header elements in shiny dashboard
However, following them did not provide enough help with my issues. Here is the reprex:
library(shiny)
library(shinydashboard)
library(shinyjs)
library(shinydashboardPlus)
library(htmltools)
library(DT)
ui <- shinydashboardPlus::dashboardPage(
options = list(sidebarExpandOnHover = TRUE),
header = shinydashboardPlus::dashboardHeader(disable = FALSE,
tags$li(class = "dropdown",
tags$a(actionButton(inputId = "email1", label = "",
icon = icon("envelope", lib = "font-awesome")
,
style='height: 20px; width: 30px;
margin-top: 0px; margin-right: 0px;
margin-bottom: 0px; padding:4px 4px 20px 4px;'
),
href="mailto:my_awesome_email_address.com")),
title = tagList(
tags$span(
class = "logo-mini", "small"
),
tags$span(
class = "logo-lg", "LONGER TEXT"
)
)),
sidebar = shinydashboardPlus::dashboardSidebar(
minified= TRUE,
collapsed = TRUE,
sidebarMenu(
),
tags$script(JS("document.getElementsByClassName('sidebar-toggle')[0].style.visibility = 'hidden';"))
),
body = shinydashboard::dashboardBody(
tabItems(
tabItem(tabName = "mainPanel_1",
box(
)
)
),
controlbar = NULL,
footer = NULL
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Any help or hint will be greatly appreciated.
Use this style for your button:
style='height: 20px;
background: transparent;
border: none;
font-size: 2rem;
transform: translate(5%, -30%);'

Math mode in bsTooltip in shiny

I'm wondering whether these is any option to include math mode in tooltip title using bsTooltip() from shinyBS package.
Small example:
rm(list = ls())
library(shiny)
library(shinyBS)
ui <- basicPage(
headerPanel("Tooltip test"),
bsTooltip(id = "Equation", title = "\\(\\bar{X} = \\frac{1}{n}\\sum_{p = 1}^{n}X_p\\)", placement = "bottom", trigger = "hover", options = NULL),
mainPanel(
p("some text", htmlOutput("Equation", inline = TRUE))
)
)
server <- shinyServer(function(input, output,session) {
output$Equation <- renderUI({HTML("<font color='blue'><u>something which needs equation</u></font>")})
})
shinyApp(ui = ui, server = server)
The result (math mode) is not satisfactory:
No way with 'shinyBS'.
Here is a way using the qTip2 JavaScript library.
In order to use it, you have to download the files jquery.qtip.min.css and jquery.qtip.min.js, and put these two files in the www subfolder of the Shiny app.
library(shiny)
js <- "
$(document).ready(function() {
$('#Equation').qtip({
overwrite: true,
content: {
text: $('#tooltip')
},
position: {
my: 'top left',
at: 'bottom right'
},
show: {
ready: false
},
hide: {
event: 'unfocus'
},
style: {
classes: 'qtip-youtube qtip-rounded'
},
events: {
blur: function(event, api) {
api.elements.tooltip.hide();
}
}
});
});
"
library(shiny)
ui <- basicPage(
tags$head(
tags$link(rel = "stylesheet", href = "jquery.qtip.min.css"),
tags$script(src = "jquery.qtip.min.js"),
tags$script(HTML(js)),
),
withMathJax(),
headerPanel("Tooltip test"),
mainPanel(
p("some text", htmlOutput("Equation", inline = TRUE)),
div(
id = "tooltip", style = "display: none;",
HTML("$$\\int_0^1 f(x) dx = \\pi$$")
)
)
)
server <- shinyServer(function(input, output,session) {
output$Equation <-
renderUI({HTML("<font color='blue'><u>something which needs equation</u></font>")})
})
shinyApp(ui = ui, server = server)
Just to add another option, we could create our own tooltip class following the example from W3 here. Then we can use {shiny}'s withMathJax() function to render the tooltip as formula.
I usually use custom tooltips in cases where I only have a few tooltips that I want to customize. It has the advantage that it comes with no additional dependencies. The major drawbacks of this custom tooltip are that (1) it is displayed as child element and not in a separate container on the top layer like tooltips generated with javascript and that (2) you have to create css classes for each arrow direction. So if you have many tooltips pointing in different directions an additional javascript library like qTip2 should be definitely worth the dependency.
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(HTML(
# tooltip implementation from:
# https://www.w3schools.com/css/tryit.asp?filename=trycss_tooltip_arrow_top
# just added a `t` to make classes unique
".ttooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.ttooltip .ttooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
top: 150%;
left: 50%;
margin-left: -60px;
}
.ttooltip .ttooltiptext::after {
content: '';
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent black transparent;
}
.ttooltip:hover .ttooltiptext {
visibility: visible;
}")
)
),
headerPanel("Tooltip test"),
mainPanel(
p("some text", htmlOutput("Equation", inline = TRUE)),
))
server <- shinyServer(function(input, output,session) {
output$Equation <- renderUI({
span(class = "ttooltip",
style = "color: blue",
"something which needs equation",
span(class = "ttooltiptext",
withMathJax("$$\\bar{X} = \\frac{1}{n}\\sum_{p = 1}$$"))
)
})
})
shinyApp(ui = ui, server = server)

Dynamic Download Button

Hi I have a problem with a download button in my Shiny APP. I have created the button dynamically when the corresponding DF has been created. Now I have the problem that the download doesn't work. If I created the button directly the download works.
I did the same with a reset function and everything works here.
Can someone tell me what I am doing wrong?
This is the Button Code in the UI:
column(3, offset = 0, uiOutput("download.action", style = "text-align: center;"))
and my Server code looks like this:
output$download.action <- renderUI({
div(style = "display:inline-block;width:0%;", actionButton("downloadData", "Download", icon = icon("download"),
style = "
flex-grow: 1;
display: inline-block;
background-color:#999;
text-decoration: none;
font-weight: 300;
border: 1px dash transparent;
letter-spacing: 0.98pt;
border-color:#00245d;"))
})
output$downloadData <- downloadHandler(
filename = function() {
paste("test.xlsx")
},
content = function(file) {
write.xlsx(test3, file, row.names = FALSE)
}
)
})
When I create the Button directly everything works fine.
Shiny gives no Error Messages. Only the Button didn't work.
You should replace actionButton with downloadButton.
output$download.action <- renderUI({
div(style = "display:inline-block;width:0%;", downloadButton("downloadData", "Download", icon = icon("download"),
style = "
flex-grow: 1;
display: inline-block;
background-color:#999;
text-decoration: none;
font-weight: 300;
border: 1px dash transparent;
letter-spacing: 0.98pt;
border-color:#00245d;"))
})

Shiny: Different styles for textInputs and selectInputs

I have 2 textInput and 2 selectInput functions. One on the dark background on my sidebar and the other on the white (inside the bsModal). My question is: is there a way to style them in different ways? Ideally, I would like to keep the ones on the sidebar the way I styled, and for the ones inside bsModal at least change font color and a border color.
Code:
## Shiny
library(shiny)
library(shinydashboard)
library(shinyBS)
ui <- dashboardPage(
## Header ----
dashboardHeader(
disable = TRUE
),
## Sidebar ----
dashboardSidebar(
sidebarMenu(
div(style = "border-left-color: #1e282c; padding: 10px",
menuItem(text = div(HTML("<left>Search</left>")),
tabName = "search",
icon = icon("search", "fa-2x"))
)
)
),
## Body ----
dashboardBody(
## when header is disabled need to compensate for the missing 50px
## to avoid empty space on the bottom
tags$script('window.onload = function() {
function fixBodyHeight() {
var el = $(document.getElementsByClassName("content-wrapper")[0]);
var h = el.height();
el.css("min-height", h + 50 + "px");
};
window.addEventListener("resize", fixBodyHeight);
fixBodyHeight();
};'),
tags$style(HTML(
"
.well{
background-color: #222C3C;
color: #FFFFFF;
}
.form-control {
background-color: transparent;
border: 0px;
border-bottom: 1px solid #ffffff;
color: #ffffff;
}
.selectize-input{
background: transparent;
}
.selectize-input.items.not-full.has-options {
border: 0px;
border-bottom: 1px solid #ffffff;
border-radius: 0;
}
.selectize-dropdown, .selectize-input, .selectize-input input{
color: #FFFFFF;
}
.selectize-control.multi .selectize-input > div{
background: rgb(9, 231, 178, 0.3);
color: #ffffff;
}
.selectize-dropdown-content {
background: #1B2431;
color: #ffffff;
border-radius: 4px;
}
.selectize-input.full{
background-color: transparent;
color: #FFFFFF;
border: 0px;
border-bottom: 1px solid #ffffff;
border-radius: 0;
}
.selectize-input, .selectize-control.single, .selectize-input.input-active{
background: transparent !important;
}
"
)),
# includeCSS("www/style.css"),
tabItems(
tabItem(
tabName = "search",
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel(div("Search task"),
textInput("searchTextIn", HTML("<i class='fa fa-search'></i> KEYWORDS"), value = ""),
selectizeInput("productFilter", HTML("<i class='fa fa-share-alt gly-rotate-135'></i> PRODUCT OR COMPONENT"),
choices = c("A", "AAA", "B", "BBBBBB", "C", "CCCCCC"),
multiple = TRUE,
selected = c("A", "AAA")),
actionLink("saveToGroup", HTML("<u> Save to group </u>"), style = "color: #d3d3d3cf"),
width = 3)
)),
mainPanel(
bsModal("saveToGroupPopup", "Save to group", "saveToGroup",
div(selectizeInput("saveToGroupSelection",
"Add this search to a search group:",
choices = c("Category A", "Category B", "Category C",
"Batman"),
selected = NULL,
multiple = TRUE,
options = list(maxItems = 1))),
textInput("saveToGroupNew", label = NULL, value = "",
placeholder = "Create new…")
)
)
)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
you can use glamor to style your inputs differently. Basically glamor allows you to write css using javascript like conditions. just pass a boolean variable along with the class and on the basis of that variable choose the style of text field for example
const descDiv = **isDark** => css({
color: isDark ? color.white : colors.gray,
marginBottom: isDark? '0rem' :'1rem',
letterSpacing:isDark ? '0px' :'-0.6px', //if isDark true 0px else -0.6px
width:isDark? '10rem' :'13.5rem'
});
One solution that worked for me is for the textInput is actually quite easy, all I needed to do is in my css:
textInput(id, "")
tags$style(HTML("
#id.form-control{color:gray;}
"))
For the selectize input is a bit more confusing:
selectizeInput(id, ....)
tags$style(HTML("
#id + div>.selectize-input.items.not-full.has-options{border-bottom: 1px solid #F2F2F2;}
#id + div>.selectize-dropdown, #id+ div>.selectize-input, #id+ div>.selectize-input input{ color: gray;}
#id + div> div> .item {color: gray;}
"))

Resources