Change color of action button - r

I would like to know if it is possible to change the color of an actionButton within an observeEvent.
In ui I have :
actionButton("bell","",icon=icon("bell"),
class = "btn action-button",
style = "color: white;
background-color: blue")
In server.R, my observeEvent is :
observeEvent(data_moment[1,c("facebook")]=="NA", {
disable("bell")
})
What I want :
If data_moment[1,c("facebook")]=="NA" I would like to disable the bell button, and set its color to grey.
Do you know how I can do ?

Just add a css rule for disabled Buttons in you css file
.btn.disabled {
background-color: red;
}
if you don't have any separate css-file you can add it to your UI with a script tag like this
library(shiny)
runApp(shinyApp(
ui = fluidPage(
shinyjs::useShinyjs(),
tags$style(".btn.disabled {
background-color: red;
}"),
actionButton("test", "Test"),
actionButton("submit", "Choose")
),
server = function(input, output, session) {
observeEvent(input$submit, {
shinyjs::disable("test")
})
}
))

Based on this answer
Ui:
uiOutput("button")
Server:
output$button <- renderUI({
if(is.na(data_moment[1,c("facebook")])){
actionButton(inputId= "bell","",
style = "color: white;
background-color: ...;
")
disable("bell")
}
else {
actionButton(inputId= "bell","",
style = "color: white;
background-color: blue;
")}
})

Related

Change color of Slider Text Input Widget in Shiny R?

Is there a way to change the color of the following slide of the CRAN package shinyWidgets? Thanks in advance. I need to do it also in within the update function.
library("shiny")
library("shinyWidgets")
ui <- fluidPage(
br(),
sliderTextInput(
inputId = "mySliderText",
label = "Month range slider:",
choices = month.name,
selected = month.name[c(4, 7)]
),
verbatimTextOutput(outputId = "result")
)
server <- function(input, output, session) {
output$result <- renderPrint(str(input$mySliderText))
}
shinyApp(ui = ui, server = server)
This can be achieved with CSS applied to the input.
Here I changed the color properties of the CSS class of the input. Which mean it will apply to all slider text input of your app. If you want to apply the color only on one input, you need to apply the CSS properties on the class children of the input ID.
The easiest way to find out how to change an element in CSS is to play with the browser inspector (CTRL+shift+i) when your app is running.
library("shiny")
library("shinyWidgets")
ui <- fluidPage(
tags$style(HTML("
.irs--shiny .irs-bar {
background: blueviolet;
border-top: 1px solid blueviolet;
border-bottom: 1px solid blueviolet;
}
.irs--shiny .irs-to, .irs--shiny .irs-from {
background-color: blueviolet;
}
.irs--shiny .irs-handle {
border: 1px solid #c41818;
background-color: #c41818;
}")),
br(),
sliderTextInput(
inputId = "mySliderText",
label = "Month range slider:",
choices = month.name,
selected = month.name[c(4, 7)]
),
verbatimTextOutput(outputId = "result")
)
server <- function(input, output, session) {
output$result <- renderPrint(str(input$mySliderText))
}
shinyApp(ui = ui, server = server)

R Shiny - Popup window when hovering over icon

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.

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)

Applying 2 different CSS styles on Shiny Button

I am developing a R Shiny Application that use the shinyWidgets library. I use 2 times the radioGroupButtons widget. I would like to make it green the first time, and red the second time, using CSS. (In reality I want to make more customisation).
Here is a basic code, applying CSS to every buttons. How can I apply 2 CSS classes?
Thank you very very much for your help !
library("shinyWidgets")
library(shiny)
# Useless server
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$button1), col = 'skyblue', border = 'white')
})
}
# Ui
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# A CSS for every .btn button
tags$style(HTML("
.btn {
color: #2ecc71;
border: 2px #2ecc71 solid;
}
.btn:hover {
color: #fff;
background-color: #2ecc71;
}
.btn-default.active, .btn-default:active, .open > .dropdown-toggle.btn-default {
color: #fff;
background-color: #2ecc71;
border-color: #2ecc71;
}
")),
# first radio button, it is green!
radioGroupButtons("button1", label = "It's green !!", choices=c("choice1"=50, "Choice2"=100, "Choice3"=150), selected=100),
# second radio button, I wish it is red!
radioGroupButtons("button2", label = "I wish I was red :( ...", choices=c("choice1"=1, "Choice2"=2), selected=1)
),
mainPanel(plotOutput("distPlot"))
)
)
shinyApp(ui = ui, server = server)
So you want to add some specific classes to your radioGroupButtons. Well, ShinyWidgets doesn't let you, so why not create your own radioButtons widget function.
(Well, this function will be almost entirely copied from radioGroupButtons)
Hint: Type radioGroupButton into the R Console to view the source code.
And lets tweak that function, such that it accepts a class argument, which will be applied to the html element. Then, you can easily access the different radioGroupButton-classes with your CSS.
Working code below:
library("shinyWidgets")
library(shiny)
# Defining the new Widget.
customRadioGroupButtons <- function (inputId, label = NULL, choices, selected = NULL, status = "default", size = "normal", direction = "horizontal", justified = FALSE, individual = FALSE, checkIcon = list(), class=NULL) {
choices <- shinyWidgets:::choicesWithNames(choices)
if (!is.null(selected) && length(selected) > 1)
stop("selected must be length 1")
if (is.null(selected))
selected <- choices[1]
size <- match.arg(arg = size, choices = c("xs", "sm", "normal",
"lg"))
direction <- match.arg(arg = direction, choices = c("horizontal",
"vertical"))
status <- match.arg(arg = status, choices = c("default",
"primary", "success", "info", "warning", "danger"))
divClass <- if (individual)
""
else "btn-group"
if (!individual & direction == "vertical") {
divClass <- paste0(divClass, "-vertical")
}
if (justified) {
divClass <- paste(divClass, "btn-group-justified")
}
if (size != "normal") {
divClass <- paste0(divClass, " btn-group-", size)
}
# Below here, the paste call is the only difference to the original function.
radioGroupButtonsTag <- tagList(tags$div(id = inputId, class = paste("radioGroupButtons", class),
if (!is.null(label))
tags$label(class = "control-label", `for` = inputId, label),
if (!is.null(label))
br(), style = "margin-top: 3px; margin-bottom: 3px; ", style = if (justified) "width: 100%;",
tags$div(class = divClass, role = "group",
`aria-label` = "...", `data-toggle` = "buttons",
class = "btn-group-container-sw", shinyWidgets:::generateRGB(inputId, choices, selected, status, size, checkIcon))))
shinyWidgets:::attachShinyWidgetsDep(radioGroupButtonsTag)
}
# Useless server
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$button1), col = 'skyblue', border = 'white')
})
}
# Ui
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# Note: Consider making a function if you use this more often.
tags$style(HTML("
.radioGroupButtons.green .btn {
color: #2ecc71;
border: 2px #2ecc71 solid;
}
.radioGroupButtons.green .btn:hover {
color: #fff;
background-color: #2ecc71;
}
.radioGroupButtons.green .btn-default.active, .radioGroupButtons.green .btn-default:active, .radioGroupButtons.green .open > .dropdown-toggle.btn-default {
color: #fff;
background-color: #2ecc71;
border-color: #2ecc71;
}
.radioGroupButtons.red .btn {
color: #EE102B;
border: 2px #EE102B solid;
}
.radioGroupButtons.red .btn:hover {
color: #fff;
background-color: #EE102B;
}
.radioGroupButtons.red .btn-default.active, .radioGroupButtons.green .btn-default:active, .radioGroupButtons.green .open > .dropdown-toggle.btn-default {
color: #fff;
background-color: #EE102B;
border-color: #EE102B;
}
")),
# first radio button, it is green!
customRadioGroupButtons("button1", class="green", label = "It's green !!", choices=c("choice1"=50, "Choice2"=100, "Choice3"=150), selected=100),
# second radio button, I wish it is red!
customRadioGroupButtons("button2", class="red", label = "I wish I was red :( ...", choices=c("choice1"=1, "Choice2"=2), selected=1)
),
mainPanel(plotOutput("distPlot"))
)
)
shinyApp(ui = ui, server = server)
You can add a Bootstrap status then overwrite the class, for example if you add status = "danger", buttons will have class btn-danger :
I can remove the limitation to valid Bootstrap status in the function, it could be useful for such styling (fill an issue here so i remenber).
library("shinyWidgets")
library("shiny")
# Useless server
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$button1), col = 'skyblue', border = 'white')
})
}
# Ui
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# A CSS for every .btn button
tags$style(HTML("
.btn-success.btn {
color: #2ecc71;
background-color: #fff;
border: 2px #2ecc71 solid;
}
.btn-success.btn:hover {
color: #fff;
background-color: #2ecc71;
}
.btn-success.active {
color: #fff;
background-color: #2ecc71;
border-color: #2ecc71;
}
.btn-danger.btn {
color: #EE102B;
background-color: #fff;
border: 2px #EE102B solid;
}
.btn-danger.btn:hover {
color: #fff;
background-color: #EE102B;
}
.btn-danger.active {
color: #fff;
background-color: #EE102B;
border-color: #EE102B;
}
")),
# first radio button, it is green!
radioGroupButtons("button1", label = "It's green !!", status = "success", choices=c("choice1"=50, "Choice2"=100, "Choice3"=150), selected=100),
# second radio button, I wish it is red!
radioGroupButtons("button2", label = "I wish I was red :( ...", status = "danger", choices=c("choice1"=1, "Choice2"=2), selected=1)
),
mainPanel(plotOutput("distPlot"))
)
)
shinyApp(ui = ui, server = server)

Add text on right of shinydashboard header

How do I add text to the right of a dashboard header sidebar icon? It seems that previous similar solutions no longer work under updates to dashboardHeader().
This is what I am trying to do in a basic shinydashboard setting:
I can use the strategy from this answer to get text in the header, but it's right-justified (which I can likely fix custom css) and also feels pretty hacky.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(dashboardHeader(title = "demo",
tags$li(class = "dropdown",
tags$p("foo")
)
), dashboardSidebar(), dashboardBody())
server <- function(input, output) { }
shinyApp(ui, server)
Is there a better way to do this?
The dashboardHeader is expecting elements of type dropdownMenu. So it will be hard to find a not hacky solution. The possible (hacky) options are: a) Modify the dashboardHeader function, or b) use some JavaScript code to add the text after creating the header. Below is my attempt to solve your problem using JavaScript, maybe it could help you.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
title = "demo"
),
dashboardSidebar(),
dashboardBody(
tags$head(tags$style(HTML(
'.myClass {
font-size: 20px;
line-height: 50px;
text-align: left;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
padding: 0 15px;
overflow: hidden;
color: white;
}
'))),
tags$script(HTML('
$(document).ready(function() {
$("header").find("nav").append(\'<span class="myClass"> Text Here </span>\');
})
'))
)
)
server <- function(input, output) { }
shinyApp(ui, server)
Adding to Geovany & Tiffany's answers, if you'd like the text content to be dynamic, you can have it change based on user input with the shinyjs::html function.
For example, I'm using it to display the name of the selected tab in the header. You can access the selected tab name in the server function as long as you have given the sidebar menu an id, in my case this is tabs.
I also had to add an id to the div that is appended to the header in Geovany's code, in this case pageHeader.
Then adding this to the server function will change the header text to display the selected tab, with switch being used to create a more presentable header format. Note the useShinyJs() in dashboardPage parameters:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
title = "demo"
),
dashboardSidebar(),
dashboardBody(
tags$head(tags$style(HTML(
'.myClass {
font-size: 20px;
line-height: 50px;
text-align: left;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
padding: 0 15px;
overflow: hidden;
color: white;
}
'))),
tags$script(HTML('
$(document).ready(function() {
$("header").find("nav").append(\'<div id="pageHeader" class="myClass"></div>\');
})
'))
),
useShinyjs()
)
server <- function(input, output) {
observeEvent(input$tabs, {
header <- switch(input$tabs,
tab1 = "Tab 1",
tab2 = "Tab 2",
tab3 = "Tab 3")
# you can use any other dynamic content you like
shinyjs::html("pageHeader", header)
})
}
shinyApp(ui, server)
A slightly modified version of Geovany's code to customize font auto-sizing, placement etc. would be:
ui.R file in directory1 containing:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
title = "demo"
),
dashboardSidebar(),
dashboardBody(
tags$script(HTML('
$(document).ready(function() {
$("header").find("nav").append(\'<div class="myClass"> Text Here </div>\');
})
')),
tags$head(
# Include our custom CSS
includeCSS("styles.css"),
)
)
)
server.R file in directory1 containing:
library(shiny)
library(shinydashboard)
server <- function(input, output) { }
a css style sheet (style.css in directory1) that controls the text parameters on resizing windows with a defined maximum size and unlimited shrink with the following code:
.myClass {
line-height: 50px;
text-align: center;
font-family: "Arial";
padding: 0 15px;
color: black;
font-size: 2vw;
}
#media (min-width: 1200px) {
.myClass {
line-height: 50px;
text-align: center;
font-family: "Arial";
padding: 0 15px;
color: black;
font-size: x-large
}
}
run using:
shiny::runApp("path to directory1")
Adding the padding properties can be a possible fix. Other options such as width, border and margin can be explored based on your requirements.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(dashboardHeader(title = "demo",
tags$li(class = "dropdown",
style = "padding: 10px 1200px 0px 0px;",
tags$p("foo")
)
), dashboardSidebar(), dashboardBody())
server <- function(input, output) { }
shinyApp(ui, server)
Hope this helps!

Resources