Position tippy tooltip next to button in R Shiny - r

I would like to add a tooltip to a button using tippy 1.0.0.
The tooltip always appears in the middle of the screen and not close to the text as expected.
I tried to specifiy the position arguments, but had no success. I was able to position the tooltips correctly in tippy version 0.1.0.
How can I position the tooltip close to the text?
library(shiny)
library(tippy)
shinyApp(
ui = fluidPage(
tippy(
element = p("Test"),
content = "Tooltip"
)
),
server = function(input, output) {}
)
Result:

This is because your tags are displayed as block in CSS. Even though the element only shows a small portion of the total width, but it is still occupying the full width of the parent node by default. This is how CSS display works. tippy works on the whole occupied width, not what you see with your eyes. Use your p tag for example to inspect:
See the blue shade that takes the entire row? tippy is displayed at the center of the shade.
We can change the display to another to force the tooltip to be positioned around p, like inline-block:
library(shiny)
library(tippy)
shinyApp(
ui = fluidPage(
tippy(
element = p(
"Test",
style = "display: inline-block"
),
content = "Tooltip"
)
),
server = function(input, output) {}
)
When you inspect, the size is what we want.
However (there is always a however), this may mess up your UI display. e.g., we want a button in the second line, but here is what you will see
library(shiny)
library(tippy)
shinyApp(
ui = fluidPage(
tippy(
element = p(
"Test",
style = "display: inline-block"
),
content = "Tooltip"
),
tags$button("Test2")
),
server = function(input, output) {}
)
To fix, you can add a wrapper outside your tooltip tag with block display,
shinyApp(
ui = fluidPage(
div(style = "display: block",
tippy(
element = p(
"Test",
style = "display: inline-block"
),
content = "Tooltip"
)
),
tags$button("Test2")
),
server = function(input, output) {}
)
Or I'd prefer an easier way:
shinyApp(
ui = fluidPage(
p(tippy(element = tags$span("Test" ), content = "Tooltip")),
tags$button("Test2")
),
server = function(input, output) {}
)
Please read more about CSS display: https://www.w3schools.com/cssref/pr_class_display.asp

Related

Aligning Multiple Action Buttons in Shiny Dashboard Header

This SO post describes how to add an actionButton to the top right of the dashboardHeader in a shinydashboard. I would like to add two action buttons next to each other in the dashboardHeader. How can I place the buttons within the header bar so that they do not overlap? More specifically, is there a way to move a button to the left and centre it vertically within the dashboardHeader?
Perhaps you are looking for this
ui <- dashboardPage(
dashboardHeader(title = div("Testing Work Space",
img(src = 'YBS.png',
title = "Just a Test Application", height = "30px"),
style = "position: relative; margin:-3px 0px 0px 5px; display:right-align;"
),
titleWidth=350,
tags$li(div(
img(src = 'YBS.png',
title = "A Test Graphics Application", height = "30px"),
style = "padding-top:15px; padding-right:100px;"),
class = "dropdown"),
tags$li(a(href = 'http://www.cnn.com',
icon("power-off"),
title = "CNN Home"),
class = "dropdown"),
tags$li(a(href = 'https://en.wikipedia.org/wiki/Mouse',
tags$img(src = 'mouse.png', height = "30px"),
title = "Mouse Home"),
class = "dropdown")
),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output,session) {}
shinyApp(ui, server)
You can adjust padding and margin to suit your needs. Also, you can add multiple actionButtons.
I can't answer your question directly because I have only used Flexdashboard. But there is a shinyWidgets package that contains a DropDown widget that allows you to embed multiple widgets into the DropDown. So if the dashboard header only allows a single widget, you could use a dropdown widget to access multiple widgets indirectly See:
http://shinyapps.dreamrs.fr/shinyWidgets/
And the dropdowns & sweetalert menu item. The sample dropdowns there contain links to the underlying shinyWidgets code.

R Shiny - customisation options not working for tippy::with_tippy()

I am trying to position a tooltip to the right of a textInput using the tippy package, however, it isn't working:
library(shiny)
library(tippy)
shinyApp(
ui = fluidPage(
with_tippy(textInput("input", "input with tooltip"), "Input text", placement = "right")
),
server = function(input, output) {}
)
The position = 'right', arrow = 'true' and theme = 'light' options also don't seem to be working.
I was wondering if this was a browser compatibility issue or if I'm missing some CSS dependencies on my end? I have tried running the app on Chrome v82.0.4068.5, Firefox 73.0.1 and Microsoft Edge 44.18362.449.0 to no avail.
Your code doesn't run because with_tippy is not a valid function.
The code below should properly show the position of the tooltip. Important to note: the tippy_this(elementId) refers back to the textInput(inputId) named THISinput here for clarity.
Instead of actually wrapping the textInput in the tippy_this, we just refer back to the input with elementId.
library(shiny)
library(tippy)
shinyApp(
ui = fluidPage(
textInput(inputId = "THISinput", "input with tooltip"),
tippy_this(elementId = "THISinput", tooltip = "Hovertext for 'THISinput' here", placement="right")
),
server = function(input, output) {}
)

R shiny navbarPage right aligned tabs

By default, using navbarPage() in shiny creates a 'static top' bootstrap page (example). If I were writing the html for a webpage, I could add a <ul> element with a class of nav navbar-nav navbar-right where the navbar-right would move the tabs/menus to the right side of the navbar.
There doesn't seem to be a way to coerce this behavior directly through the framework - is there a clever known way to accomplish this?
The solution provided by K. Rohde, especially the edit, works for keeping it nearly pure Shiny. I discovered the insertAdjacentHTML javascript function and used it to create a right-hand text label. I guess it should be possible to make tabs that Shiny knows about and can use. In my case, I was wanting to put version information on the navbar, on the right-hand side. So, adding the disabled class was to avoid confusion.
library(shiny)
app <- shinyApp(
ui = shinyUI(
fluidPage(
navbarPage("Site Title",
tabPanel("v0.1"),
tabPanel("tab1"),
tabPanel("tab2")
),
HTML("<script>var parent = document.getElementsByClassName('navbar-nav');
parent[0].insertAdjacentHTML( 'afterend', '<ul class=\"nav navbar-nav navbar-right\"><li class=\"disabled\">v0.1</li></ul>' );</script>")
)
),
server = function(input, output, session){}
)
runApp(app)
You can use shinyjs package
library(shiny)
ui <- shinyUI(
navbarPage(
'Test',
id = 'menus',
tabPanel('Test',
shinyjs::useShinyjs()),
tabPanel("Summary"),
tabPanel("Table", value = 'table')
))
server <- function(input, output, session) {
shinyjs::addClass(id = "menus", class = "navbar-right")
}
shinyApp(ui, server)
Depends on how low your expectations are.
You can add css to your UI which aligns either your tabsets or your header to the right. Code:
app <- shinyApp(
ui = shinyUI(
fluidPage(
tags$head(
tags$style(HTML("
.navbar .navbar-nav {float: right}
.navbar .navbar-header {float: right}
"))
),
navbarPage("header",
tabPanel("tab1"),
tabPanel("tab2")
)
)
),
server = function(input, output, session){}
)
runApp(app)
Edit: The header argument of navbarPage also accepts regular div-containers. (E.g. a logo instead of plain text.) This can be exploitet to fill whole UI-Elements (e.g. buttons) into the header spot. Then of course you can float that to the right, while your tabs are aligned to the left.

Plot does not resize 100% width after show/hide sidebar in R shiny page

I have a plot which is set to 100% width (default) in the main panel of a two-panel page in R Shiny. The sidebar is hideable through a toggle action button.
When the sidebar is visible (default), the plot fills the width of the main panel. When the sidebar is hidden, I want the plot to expand to fill 100% of the space now available, i.e. the whole browser window. But this does not happen! It keeps the same size.
library(shiny)
library(shinyBS)
UI <- fluidPage(
bsButton("showpanel", "Show/hide sidebar", type = "toggle", value = TRUE),
sidebarLayout(
conditionalPanel(condition = "input.showpanel == true",
sidebarPanel("This is my sidebar.")
),
mainPanel(plotOutput("plot", width = "100%"))
)
)
SERVER <- function(input, output) {
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes but not to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(UI,SERVER))
Attempted so far:
Defining the plot object from within the UI file, as above.
Defining the plot object from within the server file, as a renderUI object.
Set CSS tag in the page as per tags$head(tags$style("#myplot{height:100vh !important;}")) from this question, Scaling shiny plots to window height.
Possible work-arounds:
Make the width of the plot dynamic and depending on the state of the toggle button. Then I can make the plot e.g. 140% width when the sidebar is hidden. This does not generalise well, and loses the point of using the adaptability of fluidPage.
(fluidPage changes the layout dependent on the browser window size. For example, if you make your browser window about the size of a mobile phone, it will place the sidebar above the main panel.)
#konvas answer is really good and probably the way you wan't to do this but if you want to use the sidebarLayout (and for the sake of giving another answer) you can use jQuery to toggle the bootstrap columns like:
library(shiny)
ui <- fluidPage(
tags$head(
tags$script(
HTML("
$(document).ready(function(){
// Mark columns we want to toggle
$('body').find('div [class=col-sm-4]').addClass('sidebarPanel');
$('body').find('div [class=col-sm-8]').addClass('mainPanel');
})
Shiny.addCustomMessageHandler ('resize',function (message) {
$('.sidebarPanel').toggle();
$('.mainPanel').toggleClass('col-sm-8 col-sm-12');
$(window).trigger('resize')
});
")
)
),
actionButton("showpanel", "Show/hide sidebar"),
sidebarLayout(
sidebarPanel("This is my sidebar."),
mainPanel(plotOutput("plot", width = "100%"))
)
)
server <- function(input, output, session) {
observeEvent(input$showpanel,{
session$sendCustomMessage(type = 'resize', message = 1)
})
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes but not to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(ui,server))
The same methodology would apply if you use columns in a fluidRow or something similar.
One way to do this would be to use a reactive layout (there are many questions on this eg Switch between layouts reactively with shiny). In your case that would be something like
library(shiny)
library(shinyBS)
UI <- shinyUI(
fluidPage(
bsButton("showpanel", "Show/hide sidebar", type = "toggle", value = TRUE),
uiOutput('ui')
)
)
SERVER <- function(input, output) {
output$ui <- renderUI({
if (input$showpanel) {
sidebarLayout(
sidebarPanel("This is my sidebar."),
mainPanel(plotOutput('plot'))
)
} else {
plotOutput('plot')
}
})
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes and to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(UI,SERVER))

How can I make the width of an image in a Shiny app dynamic?

I am writing an app and I want the image in the sidebarPanel to be just a bit bigger than the image I put inside it. As the window gets smaller or larger, so does the sidebar, but the image stays static. How do I fix this problem? Is there a way to get the sidebar length or is there a better way to render images?
ui.R
library(shiny)
shinyUI(bootstrapPage(
# Application title
titlePanel("Sidebar Image App"),
sidebarPanel(
imageOutput("image", height = "auto")
)
))
server.R
library(shiny)
shinyServer(function(input, output, session) {
output$image <- renderImage({
return(list(
src = "one.png",
contentType = "image/png",
height = 185,
alt = "Face"
))
})
})
You can style the image using css tag as below:
shinyUI(bootstrapPage(
titlePanel("Sidebar Image App"),
tags$head(tags$style(
type="text/css",
"#image img {max-width: 100%; width: 100%; height: auto}"
)),
sidebarPanel(
imageOutput("image")
)
)),
where css id selector (here #image) should correspond to the outputId of the imageOutput.

Resources