Tooltips
#| standalone: true
#| components: [viewer]
#| viewerHeight: 200
from shiny import App, render, ui
app_ui = ui.page_fluid(
ui.tooltip(
ui.input_action_button("btn", "A button with a tooltip"),
"A message",
id="btn_tooltip",
placement="right",
),
ui.output_text_verbatim("text"),
)
def server(input, output, session):
@render.text
def text():
return f"Tooltip state: {input.btn_tooltip()}"
app = App(app_ui, server)
from shiny import App, render, ui
app_ui = ui.page_fluid(
ui.tooltip(
ui.input_action_button("btn", "A button with a tooltip"),
"A message",
id="btn_tooltip",
placement="right",
),
ui.output_text_verbatim("text"),
)
def server(input, output, session):
@render.text
def text():
return f"Tooltip state: {input.btn_tooltip()}"
app = App(app_ui, server)
Relevant Functions
-
ui.tooltip
ui.tooltip(trigger, *args, id=None, placement='auto', options=None, **kwargs)
-
ui.update_tooltip
ui.update_tooltip(id, *args, show=None, session=None)
Details
A tooltip is a box that appears next to an element when a user hovers over the element. To add a tooltip to a UI component, wrap the component in ui.tooltip()
. Then pass ui.tooltip()
one or more elements to display, such as a simple string that contains a message.
Optionally assign the tooltip an id
to trigger reactions when the tooltip becomes visible or to programmatically update the contents of the tooltip as your user navigates the app. A boolean that describes whether or not the tooltip is visible will be accessible as a reactive variable within the server function as input.<id>()
.
Control the placement of the tooltip relative to the item it highlights with the placement
argument. placement
defaults to 'auto'
, but can be set to one of 'top'
, 'bottom'
, 'left'
, or 'right'
.
Accessibility of Tooltip Triggers
Because the user needs to interact with the trigger
element to see the tooltip
, it’s best practice to use an element that is typically accessible via keyboard interactions, like a button or a link.
If you use a non-interactive element, like a <span>
or text, tooltip()
will automatically add the tabindex="0"
attribute to the trigger element to make sure that users can reach the element with the keyboard. This means that in most cases you can use any element you want as the trigger.
One place where it’s important to consider the accessibility of the trigger is when using an icon without any accompanying text. In these cases, many icon elements are created with the assumption that the icon is decorative, which will make it inaccessible to users of assistive technologies.
When using an icon as the primary trigger, ensure that the icon does not have aria-hidden="true"
or role="presentation"
attributes. Icon packages typically provide a way to specify a title for the icon, as well as a way to specify that the icon is not decorative. The title should be a short description of the purpose of the trigger, rather than a description of the icon itself.
For example:
icon_title = "About tooltips"
def bs_info_icon(title: str):
# Enhanced from https://rstudio.github.io/bsicons/ via `bsicons::bs_icon("info-circle", title = icon_title)`
return ui.HTML(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="bi bi-info-circle " style="height:1em;width:1em;fill:currentColor;" aria-hidden="true" role="img" ><title>{title}</title><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"></path><path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"></path></svg>')
ui.tooltip(
bs_info_icon(icon_title),
"Text shown in the tooltip."
)
icon_title = "About tooltips"
def fa_info_circle(title: str):
# Enhanced from https://rstudio.github.io/fontawesome/ via `fontawesome::fa("info-circle", a11y = "sem", title = icon_title)`
return ui.HTML(f'<svg aria-hidden="true" role="img" viewBox="0 0 512 512" style="height:1em;width:1em;vertical-align:-0.125em;margin-left:auto;margin-right:auto;font-size:inherit;fill:currentColor;overflow:visible;position:relative;"><title>{title}</title><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>')
ui.tooltip(
fa_info_circle(icon_title),
"Text shown in the tooltip."
)
Compare tooltips to popovers, which are a similar device for organizing the layout of a Shiny app.
See Also: Modal messages and notications provide a similar, but alternative way to display information to the user.
Variations
Update a tooltip message
Call ui.update_tooltip()
to update the message of a tooltip with a given id.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 300
from shiny import App, reactive, ui
app_ui = ui.page_fluid(
ui.tooltip(
ui.input_action_button("btn", "A button with a tooltip"),
"A message",
id="btn_tooltip",
placement="right",
),
ui.input_text("tooltip_msg", "Tooltip message", "Change me!").add_class("mt-4"),
)
def server(input, output, session):
@reactive.effect
@reactive.event(input.tooltip_msg)
def update_tooltip_msg():
ui.update_tooltip("btn_tooltip", input.tooltip_msg(), show=True)
app = App(app_ui, server)
from shiny import reactive
from shiny.express import input, ui
with ui.tooltip(id="btn_tooltip", placement="right"):
ui.input_action_button("btn", "A button with a tooltip")
"The tooltip message"
ui.input_text("tooltip_msg", "Tooltip message", "Change me!").add_class("mt-4")
@reactive.effect()
@reactive.event(input.tooltip_msg)
def update_tooltip_msg():
ui.update_tooltip("btn_tooltip", input.tooltip_msg(), show=True)
from shiny import App, reactive, ui
app_ui = ui.page_fluid(
ui.tooltip(
ui.input_action_button("btn", "A button with a tooltip"),
"A message",
id="btn_tooltip",
placement="right",
),
ui.input_text("tooltip_msg", "Tooltip message", "Change me!").add_class("mt-4"),
)
def server(input, output, session):
@reactive.effect
@reactive.event(input.tooltip_msg)
def update_tooltip_msg():
ui.update_tooltip("btn_tooltip", input.tooltip_msg(), show=True)
app = App(app_ui, server)