docs(skills): two silent failure modes of the hosted-widget recipe - #312
Merged
Merged
Conversation
`shiny-outputs.md`'s hosted-input recipe (#294) leads readers straight into two Shiny behaviors it does not mention, both of which fail with no error, no warning, and nothing in the console: - an `update_slider()` / `updateSliderInput()` sent before the holder has rendered targets an id the client has not bound, and is dropped. The section previously said updates "keep working against the id" with no qualifier, which is exactly the sentence that walks you in. - a holder that is not visible on first paint is suspended, so its render function never runs and no widget appears at all. Both are plain Shiny — a `output_ui()` / `uiOutput()` app with no React anywhere loses the same update and suspends the same output — but the holder recipe makes them easy to hit, so the skill now documents them. Found via samuelbharti/shinyreact-apps' upstream gap report, which verified both in R over ~20 real ports. Pinned here for Python with two new e2e tests, each with its own control so neither can pass vacuously: the update test bumps the same slider after it exists (9 -> 30), and the suspension test mounts two identical holders in one hidden panel differing only by `suspend_when_hidden=False`. Flipping that one line fails the test. R has no e2e suite yet (#194), so the R halves are the upstream report's verification plus the shared Shiny mechanism, not a test here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
shiny-outputs.md's hosted-input recipe (#294) teaches the mechanism but not the two ways it silently fails. Both produce no error, no warning, and nothing in the console — the widget just doesn't update, or doesn't appear.update_slider()/updateSliderInput()sent before the holder has rendered is dropped. The section previously said updates "keep working against the id" with no qualifier — which is exactly the sentence that walks a reader in. Guidance: put the value in the widget's own constructor call; reach forupdate_*only for a value you don't know until after the widget exists.[py]suspend_when_hidden=False/[r]suspendWhenHidden = FALSEis the opt-out.Neither is a shinyreact bug — a plain
output_ui()/uiOutput()app with no React anywhere loses the same update and suspends the same output. But the holder recipe makes both easy to walk into, which is why they belong in the skill.Where this came from
samuelbharti/shinyreact-apps
docs/upstream— a gap report from a downstream repo doing pixel-identical bslib→shinyreact ports, plus a draft patch. Their report verified both in R and explicitly flagged the Python side as unverified guesswork. This PR verifies Python.Four other findings in that report I deliberately left out:
useShinyOutputValue's auto-prefixing vs. a user-written namespace helper (the only genuinely shinyreact-specific one, but only bites if you wrap the module hooks yourself);bs_global_theme()'s first arg beingversion;loadSupport()sourcingR/beforeapp.R'slibrary()calls;page_navbar()markup varying withgetCurrentTheme(). The last three are bslib/Shiny trivia, and the fourth only bites if you hand-write navbar TSX instead of hosting it.Verification
Two new e2e tests in
pkg-py/tests/playwright/test_hosted_input_timing.py, each with a built-in control so neither can pass vacuously:test_update_before_the_holder_renders_is_dropped— startupupdate_slider(value=30), holder renders on click, slider arrives at9. Then#bumpfires the identical call once the widget exists and it lands at30. The first assertion fails if the update had been applied; the second fails if updates never work at all.test_hosted_widget_hidden_on_first_paint_never_renders— two identical holders in onedisplay: nonepanel, differing only bysession.output(suspend_when_hidden=False). Only the opted-out one exists in the DOM. Confirmed it fails when that one line is applied to both (i.e. the test triggers unless the gotcha is real).make update-skillsrun;FEATURES.mdupdated with both leaves marked(e2e)and noted as Shiny's behavior rather than ours.Not done
R halves of both claims rest on the upstream report's R verification plus the shared Shiny mechanism, not a test here — R has no e2e suite yet (#194).