From 26f3a2c6adb6f8732660c68e343b504289dd27c5 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:05:17 -0400 Subject: [PATCH 1/9] Finalize tooltip styling and triggers --- lorenz-attractor/app.R | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/lorenz-attractor/app.R b/lorenz-attractor/app.R index 16159f1..9ca3845 100644 --- a/lorenz-attractor/app.R +++ b/lorenz-attractor/app.R @@ -8,17 +8,7 @@ library(markdown) library(shinyWidgets) # theme options ----------------------------------------------------------- -apptheme <- bs_theme( - "tooltip-bg" = "$white", - "tooltip-color" = "$body-color", - "tooltip-opacity" = 1 -) |> - bs_add_rules( - ".tooltip-inner { - border: 1px solid $border-color; - box-shadow: $box-shadow-sm; - }" - ) +apptheme <- bs_theme("tooltip-bg" = "#495057") sidebar <- purrr::partial(bslib::sidebar, width = 300) @@ -63,7 +53,7 @@ ui <- page_fillable( tagList( "\\( \\sigma \\) (sigma):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1", title = "About sigma"), + bsicons::bs_icon("info-circle", class = "ms-1"), "Controls how quickly x follows y.", placement = "right", options = list(trigger = "hover focus click") @@ -79,7 +69,7 @@ ui <- page_fillable( tagList( "\\( \\rho \\) (rho):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1", title = "About rho"), + bsicons::bs_icon("info-circle", class = "ms-1"), "Controls the system's driving strength and whether chaotic behavior emerges.", placement = "right", options = list(trigger = "hover focus click") @@ -95,7 +85,7 @@ ui <- page_fillable( tagList( "\\( \\beta \\) (beta):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1", title = "About beta"), + bsicons::bs_icon("info-circle", class = "ms-1"), "Controls damping in the z direction.", placement = "right", options = list(trigger = "hover focus click") @@ -119,7 +109,7 @@ ui <- page_fillable( tagList( "Time step (dt):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1", title = "About time step"), + bsicons::bs_icon("info-circle", class = "ms-1"), "Larger steps cover more time per point but reduce numerical accuracy.", placement = "right", options = list(trigger = "hover focus click") From 7a9ab88bb33fcc541cfced6f87a6569dffc9e8a5 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:10:35 -0400 Subject: [PATCH 2/9] Finalize repository tooltip guidance --- README.md | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 70b6347..d04783f 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ If a Shinylive app cannot be exported, the build fails. Move it to the server ru ## Input Help and Tooltips -Use input tooltips conservatively. Add them only when a control represents a non-obvious statistical or mathematical concept, uses a confusing scale, changes the result conceptually, or needs context that does not fit naturally in its label. +Use input tooltips conservatively across all apps, including drafts. Add them only when a control represents a non-obvious statistical or mathematical concept, uses a confusing scale, changes the result conceptually, or needs context that does not fit naturally in its label. - Treat two to four tooltips per app as an upper limit, not a target. - Do not add help to obvious controls such as the number of observations unless there is an important non-obvious consequence. @@ -94,38 +94,32 @@ Use input tooltips conservatively. Add them only when a control represents a non - Do not repeat the general explanation already available in `readme.md`. - Preserve existing label wrappers such as `tags$small()` and the current sidebar spacing. - Use namespace-qualified calls instead of adding `library(bsicons)`. -- Give icon-only triggers a short accessible `title`. +- Do not set `title` on the icon trigger; browser-native title tooltips duplicate the `bslib` tooltip. +- For an icon-only trigger, wrap the icon in an accessible span with `role = "button"` and an `aria-label`. - Add a small spacing utility such as `class = "ms-1"` so the icon remains visually separate from the label. - Support hover, keyboard focus, and click/touch with `options = list(trigger = "hover focus click")`. -- Use a light tooltip theme with a white background, dark text, and a subtle border or shadow. +- Use the repository tooltip background `#495057`; keep the rest of the appearance on Bootstrap defaults. - Test the icon at normal and narrow widths and verify the interaction directly in the running app. -Configure the light tooltip appearance once in the app theme: +Configure the tooltip appearance once in each app that uses tooltips: ```r -apptheme <- bs_theme( - "tooltip-bg" = "$white", - "tooltip-color" = "$body-color", - "tooltip-opacity" = 1 -) |> - bs_add_rules( - ".tooltip-inner { - border: 1px solid $border-color; - box-shadow: $box-shadow-sm; - }" - ) +apptheme <- bs_theme("tooltip-bg" = "#495057") ``` +If the app already customizes `bs_theme()`, keep those settings and add `"tooltip-bg" = "#495057"` to the same call. + Use this pattern, adapting the outer wrapper to the existing label: ```r label = tags$small(tagList( "Parameter name", bslib::tooltip( - bsicons::bs_icon( - "info-circle", + tags$span( + bsicons::bs_icon("info-circle"), class = "ms-1", - title = "About parameter name" + role = "button", + `aria-label` = "About parameter name" ), "Short explanation.", placement = "right", From 9d9cab9dc523d9504fde40addf37f5fcca0572e8 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:10:46 -0400 Subject: [PATCH 3/9] Align app template tooltip theme --- app-template/app.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-template/app.R b/app-template/app.R index 43d2cbc..6b61d44 100644 --- a/app-template/app.R +++ b/app-template/app.R @@ -3,7 +3,7 @@ library(shiny) library(bslib) # theme ------------------------------------------------------------------- -apptheme <- bs_theme() +apptheme <- bs_theme("tooltip-bg" = "#495057") sidebar <- purrr::partial(bslib::sidebar, width = 300) @@ -39,4 +39,4 @@ server <- function(input, output, session) { # Add server logic here. } -shinyApp(ui, server) \ No newline at end of file +shinyApp(ui, server) From 182b428dc7fd6d8c18ced847a89af95027449c3d Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:11:34 -0400 Subject: [PATCH 4/9] Add conservative decision tree tooltips --- decision-tree/app.R | 49 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/decision-tree/app.R b/decision-tree/app.R index fb4beb0..154bf05 100644 --- a/decision-tree/app.R +++ b/decision-tree/app.R @@ -12,7 +12,7 @@ library(risk3r) # remotes::install_github("jbkunst/risk3r", force = TRUE) library(klassets) # remotes::install_github("jbkunst/klassets", force = TRUE) # theme options ----------------------------------------------------------- -apptheme <- bs_theme() +apptheme <- bs_theme("tooltip-bg" = "#495057") sidebar <- purrr::partial(bslib::sidebar, width = 300) @@ -48,7 +48,20 @@ ui <- page_fillable( ), sliderInput( "percent_noise", - tags$small("Percent noise"), + tags$small(tagList( + "Percent noise", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About percent noise" + ), + "Randomly flips this percentage of class labels, making the underlying relationship harder to learn.", + placement = "right", + options = list(trigger = "hover focus click") + ) + )), min = 0, max = 50, step = 5, @@ -57,7 +70,20 @@ ui <- page_fillable( ), sliderInput( "depth", - tags$small("Maximum depth of the tree"), + tags$small(tagList( + "Maximum depth of the tree", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About maximum tree depth" + ), + "Limits how many split levels the tree can grow; deeper trees can fit more complex boundaries.", + placement = "right", + options = list(trigger = "hover focus click") + ) + )), min = 1, max = 8, step = 1, @@ -65,7 +91,20 @@ ui <- page_fillable( ), sliderInput( "alpha", - tags$small("Significance level for variable selection \\( \\alpha \\)"), + tags$small(tagList( + "Significance level for variable selection \\( \\alpha \\)", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About alpha" + ), + "Only splits with p-values below this level are accepted; smaller values make the tree more conservative.", + placement = "right", + options = list(trigger = "hover focus click") + ) + )), min = 0, max = 1, step = 0.05, @@ -253,4 +292,4 @@ server <- function(input, output, session) { } -shinyApp(ui, server) \ No newline at end of file +shinyApp(ui, server) From 583fdc201ede1f0aac87760aba25804409fe1f7d Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:12:07 -0400 Subject: [PATCH 5/9] Add conservative logistic regression tooltips --- logistic-regression/app.R | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/logistic-regression/app.R b/logistic-regression/app.R index 03d65b0..8d19052 100644 --- a/logistic-regression/app.R +++ b/logistic-regression/app.R @@ -11,7 +11,7 @@ library(risk3r) # remotes::install_github("jbkunst/risk3r", force = TRUE) library(klassets) # remotes::install_github("jbkunst/klassets", force = TRUE) # theme options ----------------------------------------------------------- -apptheme <- bs_theme() +apptheme <- bs_theme("tooltip-bg" = "#495057") sidebar <- purrr::partial(bslib::sidebar, width = 300) @@ -47,7 +47,20 @@ ui <- page_fillable( ), sliderInput( "percent_noise", - tags$small("Percent noise"), + tags$small(tagList( + "Percent noise", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About percent noise" + ), + "Randomly flips this percentage of class labels, making the underlying relationship harder to learn.", + placement = "right", + options = list(trigger = "hover focus click") + ) + )), min = 0, max = 50, step = 5, @@ -56,7 +69,20 @@ ui <- page_fillable( ), sliderInput( "order", - tags$span("Model Order"), + tags$span(tagList( + "Model Order", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About model order" + ), + "Adds higher-order polynomial terms, allowing the logistic model to represent increasingly curved decision boundaries.", + placement = "right", + options = list(trigger = "hover focus click") + ) + )), min = 1, max = 4, step = 1, From 14b84470d10eb36b7ae62dc8f31fe16152a1ada7 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:12:39 -0400 Subject: [PATCH 6/9] Keep Lorenz tooltip triggers accessible without titles --- lorenz-attractor/app.R | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lorenz-attractor/app.R b/lorenz-attractor/app.R index 9ca3845..27a6278 100644 --- a/lorenz-attractor/app.R +++ b/lorenz-attractor/app.R @@ -53,7 +53,12 @@ ui <- page_fillable( tagList( "\\( \\sigma \\) (sigma):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1"), + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About sigma" + ), "Controls how quickly x follows y.", placement = "right", options = list(trigger = "hover focus click") @@ -69,7 +74,12 @@ ui <- page_fillable( tagList( "\\( \\rho \\) (rho):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1"), + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About rho" + ), "Controls the system's driving strength and whether chaotic behavior emerges.", placement = "right", options = list(trigger = "hover focus click") @@ -85,7 +95,12 @@ ui <- page_fillable( tagList( "\\( \\beta \\) (beta):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1"), + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About beta" + ), "Controls damping in the z direction.", placement = "right", options = list(trigger = "hover focus click") @@ -109,7 +124,12 @@ ui <- page_fillable( tagList( "Time step (dt):", bslib::tooltip( - bsicons::bs_icon("info-circle", class = "ms-1"), + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About time step" + ), "Larger steps cover more time per point but reduce numerical accuracy.", placement = "right", options = list(trigger = "hover focus click") From 4bf8549148655102a1d73b0496b6a0244b122139 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:13:35 -0400 Subject: [PATCH 7/9] =?UTF-8?q?Add=20dimensionality=20reduction=20help=20t?= =?UTF-8?q?o=20Pok=C3=A9mon=20draft?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pokemon-dimensionality-reduction/app.R | 48 +++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/pokemon-dimensionality-reduction/app.R b/pokemon-dimensionality-reduction/app.R index fabab12..b035684 100644 --- a/pokemon-dimensionality-reduction/app.R +++ b/pokemon-dimensionality-reduction/app.R @@ -29,7 +29,8 @@ apptheme <- bs_theme( bg = "#f5f7fb", fg = "#172033", primary = "#2a75bb", - secondary = "#ffcb05" + secondary = "#ffcb05", + "tooltip-bg" = "#495057" ) sidebar <- purrr::partial(bslib::sidebar, width = 305) @@ -224,7 +225,20 @@ ui <- page_fillable( "input.method === 'tsne'", sliderInput( "perplexity", - "Perplexity", + tagList( + "Perplexity", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About perplexity" + ), + "Controls the effective neighborhood size t-SNE tries to preserve; larger values emphasize broader structure.", + placement = "right", + options = list(trigger = "hover focus click") + ) + ), min = 5, max = 100, value = 40, @@ -243,7 +257,20 @@ ui <- page_fillable( "input.method === 'umap'", sliderInput( "n_neighbors", - "Neighbors", + tagList( + "Neighbors", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About UMAP neighbors" + ), + "Controls how many nearby observations UMAP uses to define local structure; larger values emphasize broader patterns.", + placement = "right", + options = list(trigger = "hover focus click") + ) + ), min = 2, max = 100, value = 30, @@ -251,7 +278,20 @@ ui <- page_fillable( ), sliderInput( "min_dist", - "Minimum distance", + tagList( + "Minimum distance", + bslib::tooltip( + tags$span( + bsicons::bs_icon("info-circle"), + class = "ms-1", + role = "button", + `aria-label` = "About UMAP minimum distance" + ), + "Controls how tightly UMAP can pack nearby points in the embedding; smaller values form denser clusters.", + placement = "right", + options = list(trigger = "hover focus click") + ) + ), min = 0, max = 0.95, value = 0.15, From ac457d1b1b52133223d5cf8ff0f733396a9d9d8c Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:15:04 -0400 Subject: [PATCH 8/9] Avoid duplicating logistic regression README help --- logistic-regression/app.R | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/logistic-regression/app.R b/logistic-regression/app.R index 8d19052..03d65b0 100644 --- a/logistic-regression/app.R +++ b/logistic-regression/app.R @@ -11,7 +11,7 @@ library(risk3r) # remotes::install_github("jbkunst/risk3r", force = TRUE) library(klassets) # remotes::install_github("jbkunst/klassets", force = TRUE) # theme options ----------------------------------------------------------- -apptheme <- bs_theme("tooltip-bg" = "#495057") +apptheme <- bs_theme() sidebar <- purrr::partial(bslib::sidebar, width = 300) @@ -47,20 +47,7 @@ ui <- page_fillable( ), sliderInput( "percent_noise", - tags$small(tagList( - "Percent noise", - bslib::tooltip( - tags$span( - bsicons::bs_icon("info-circle"), - class = "ms-1", - role = "button", - `aria-label` = "About percent noise" - ), - "Randomly flips this percentage of class labels, making the underlying relationship harder to learn.", - placement = "right", - options = list(trigger = "hover focus click") - ) - )), + tags$small("Percent noise"), min = 0, max = 50, step = 5, @@ -69,20 +56,7 @@ ui <- page_fillable( ), sliderInput( "order", - tags$span(tagList( - "Model Order", - bslib::tooltip( - tags$span( - bsicons::bs_icon("info-circle"), - class = "ms-1", - role = "button", - `aria-label` = "About model order" - ), - "Adds higher-order polynomial terms, allowing the logistic model to represent increasingly curved decision boundaries.", - placement = "right", - options = list(trigger = "hover focus click") - ) - )), + tags$span("Model Order"), min = 1, max = 4, step = 1, From 3c48c00fed2a6372b75d1a531c30ed7a3c627ce0 Mon Sep 17 00:00:00 2001 From: Joshua Kunst Date: Wed, 29 Jul 2026 22:15:39 -0400 Subject: [PATCH 9/9] Keep decision tree help non-duplicative --- decision-tree/app.R | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/decision-tree/app.R b/decision-tree/app.R index 154bf05..297230d 100644 --- a/decision-tree/app.R +++ b/decision-tree/app.R @@ -70,20 +70,7 @@ ui <- page_fillable( ), sliderInput( "depth", - tags$small(tagList( - "Maximum depth of the tree", - bslib::tooltip( - tags$span( - bsicons::bs_icon("info-circle"), - class = "ms-1", - role = "button", - `aria-label` = "About maximum tree depth" - ), - "Limits how many split levels the tree can grow; deeper trees can fit more complex boundaries.", - placement = "right", - options = list(trigger = "hover focus click") - ) - )), + tags$small("Maximum depth of the tree"), min = 1, max = 8, step = 1, @@ -91,20 +78,7 @@ ui <- page_fillable( ), sliderInput( "alpha", - tags$small(tagList( - "Significance level for variable selection \\( \\alpha \\)", - bslib::tooltip( - tags$span( - bsicons::bs_icon("info-circle"), - class = "ms-1", - role = "button", - `aria-label` = "About alpha" - ), - "Only splits with p-values below this level are accepted; smaller values make the tree more conservative.", - placement = "right", - options = list(trigger = "hover focus click") - ) - )), + tags$small("Significance level for variable selection \\( \\alpha \\)"), min = 0, max = 1, step = 0.05,