shinyjs, common JavaScript operations for Shiny apps without writing JavaScript
💡 Easily improve the user experience of your Shiny apps in seconds
At a glance
- What is it?
- daattali/shinyjs gives Shiny developers a set of R functions that hide and show elements, enable and disable inputs, reset widgets, delay code and fire events, so a UI tweak does not require hand-written JavaScript in a custom message handler. It is one of a family of small Shiny packages by the same author.
- Who is it for?
- Adopt shinyjs if you maintain Shiny apps and need small interactive behaviours that Shiny's reactive model does not cover, especially showing and hiding panels and enabling inputs conditionally. Skip it if your app needs complex client-side interaction, because then you need real JavaScript with a custom message handler rather than a helper for the common cases.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 75 days ago.
- What is it written in?
- Mainly R, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the package is for
shinyjs lets you perform common, useful JavaScript operations in Shiny apps without having to know any JavaScript. The examples the README gives are hiding an element, disabling an input, resetting an input back to its original value, delaying code execution by a few seconds, and many more useful functions for both the end user and the developer.
The problem it solves is one every Shiny developer hits. Shiny's reactive model is excellent at recomputing outputs when inputs change, but it has no built-in way to change the state of the page itself. Hiding a panel until a certain condition is met, or disabling a submit button while a job runs, means dropping down to custom JavaScript through Shiny's message passing mechanism, which is a non-trivial detour for something as common as a conditional panel.
shinyjs puts a thin, documented layer over that mechanism so the common operations are one R call each. It can also be used to call your own custom JavaScript functions from R, which makes it a bridge rather than a closed set of features.
The one precondition is stated in a note above the function table, and it is the thing that catches people out: in order to use any shinyjs function in a Shiny app, you must first call useShinyjs() anywhere in the app's UI. The reason is that the package has to inject its JavaScript and set up the message handling before any of its own functions can be called, and that has to happen when the page is built rather than later from a reactive context.
The package is by Dean Attali, and the README links to an official website at deanattali.com/shinyjs. The repository is not archived and the last push was on 2026-08-11, so it is still being worked on, though the release history is old: v1.1 in January 2020, 2.0.0 in September 2020 and 2.1.0 in December 2021.
The licence field on the repository says it is a custom licence GitHub cannot classify, so read the LICENSE file before shipping it in a commercial product.
The function set, grouped by what it changes
The overview table groups the functions by the kind of state they touch, and reading it that way is more useful than reading it alphabetically.
Visibility is the largest group. show, hide and toggle display or hide an element, optionally with an animation. hidden is the initial-state version: it initialises a Shiny tag as invisible so it can be shown later with a call to show.
Input state is the second group. enable, disable and toggleState enable or disable an input element such as a button or a text input, and disabled is the initial-state version for an input, which is how you ship a form with a button greyed out until the user has filled something in.
Then there are the value operations. reset puts a Shiny input widget back to its original value, which is what you want after a submission succeeds. refresh reloads the page. html changes the text or HTML of an element, which is the way to update a status line that is not a Shiny output.
Timing and events form the third group. delay executes R code, including any shinyjs functions, after a specified amount of time. click simulates a click on a button, which is how you chain one action to another. onclick runs R code when a specific element is clicked, and the README notes it was originally developed with the sole purpose of running a shinyjs function on click, though any R code can be used. onevent is the generalisation: similar to onclick, but for many other events such as a key press or a mouse hover. removeEvent removes an event added to an HTML element.
alert shows a message to the user.
That last one overlaps with a sibling package, and the README is explicit that shinyjs is part of a larger ecosystem of packages with a shared vision of solving common Shiny issues with minimal effort and clear documentation. The siblings are shinyalert for popup modals, shinyscreenshot for capturing pages, timevis for timelines, shinycssloaders for loading animations, colourpicker for colours, shinybrowser for browser information, shinydisconnect for disconnect messages, and shinytip, shinymixpanel and shinyforms which are marked work in progress.
The existence of shinyalert alongside alert suggests the dedicated package is the more complete way to show modal messages.
The ecosystem around it and the documentation approach
The sibling packages are the clearest evidence of what the author is trying to build. Each one covers a single recurring Shiny need, and each has a demo linked from the README.
shinyalert handles pretty popup messages. shinyscreenshot captures screenshots of entire pages or parts of pages. timevis builds interactive timeline visualisations in R. shinycssloaders adds a loading animation to a Shiny output while it is recalculating, which addresses a genuine problem: a Shiny output that takes two seconds is indistinguishable from a broken one. colourpicker provides a colour picker for Shiny and for selecting colours in plots. shinybrowser finds out information about a user's web browser. shinydisconnect shows a nice message when an app disconnects or errors, which is what you want when a user's session dies on a long job.
shinytip, shinymixpanel and shinyforms are listed with work in progress markers, and shinymixpanel covers tracking user interactions in Mixpanel from Shiny apps or R scripts, and shinyforms covers questionnaire-style forms.
The shinyjs site has a demo Shiny app where you can try the functionality, a 30 minute video of a talk from the 2016 Shiny Developer Conference, and a five minute user-facing talk from the 2016 useR Conference, both with presentation slides.
The hex sticker in the repository follows the same pattern: show the outcome rather than describe it.
The sponsorship section is worth a note, because it says how the project is funded. There are no sponsors yet, and there is an invitation to become the first sponsor with a set of rewards attached. The README also mentions that the author is available for Shiny consulting, and asks for sponsorship of the work generally. For a package on CRAN that many people depend on, that is a real consideration, and it is the kind of thing a team should look at before depending on a single-maintainer package in a long-lived application.
How to use it and what to check
The usage pattern is short. Call useShinyjs() once in the app's UI, typically near the top of the fluidPage or in the body of the main panel. Then use the functions in reactive expressions or in observers, and the change appears in the browser.
The first thing to verify when you install it is that useShinyjs() is actually being called, because without it every shinyjs call fails in a way that can be confusing. The error tends to surface as the function not doing anything rather than as a clear message, because the package's JavaScript was never injected.
The second thing to check is the interaction with Shiny's own reactivity, which is where the interesting bugs live. A show call inside a reactive expression will fire whenever the expression re-evaluates, so if the expression depends on an input that changes often, the element will flicker. The usual fix is to guard the call so it only acts on a change in the condition rather than on every re-evaluation, and the README's FAQ and extra tricks section is where that advice lives.
The third is that these functions change the page, and Shiny does not know the page changed. If the user has scrolled somewhere and you then hide an element above them, the scroll position does not adjust, and the layout can end up somewhere the user did not expect. A CSS transition or a scroll adjustment is often needed alongside a show or hide.
The fourth is accessibility. Hiding an element with display none removes it from the accessibility tree as well as from view, which is usually what you want, but it also means a screen reader user loses the context of what the panel was for. And disabling an input is better than hiding it for that reason, since a disabled control is still announced.
The version question is the last. The CRAN release is 2.1.0 from December 2021, with the source repository having been pushed to more recently. If your organisation pins package versions for reproducibility, note that the CRAN version is the one you will get from install.packages, and it is now several years old, so check the NEWS.md file for what changed since.
Editorial conclusion
Adopt shinyjs if you maintain Shiny apps and need small interactive behaviours that Shiny's reactive model does not cover, especially showing and hiding panels and enabling inputs conditionally. Skip it if your app needs complex client-side interaction, because then you need real JavaScript with a custom message handler rather than a helper for the common cases. Verify first by calling useShinyjs() in the UI, since the README states that no shinyjs function works without it, and then test one conditional show or hide in a development app.
Frequently asked questions
What does the shinyjs package do?
It provides R functions that perform common JavaScript operations in Shiny apps without the developer writing JavaScript, including hiding and showing elements, enabling and disabling inputs, resetting an input to its original value, delaying code execution, changing an element's HTML and firing clicks and other events.
What must I do before using any shinyjs function?
You must first call useShinyjs() somewhere in the app's UI. The README states this explicitly, and it is required because the package has to inject its JavaScript and set up message handling when the page is built.
Which shinyjs functions change the state of an input?
enable, disable and toggleState enable or disable an input element such as a button or text input, disabled initialises an input as disabled, and reset puts a Shiny input widget back to its original value. The show, hide and toggle trio handle visibility, and hidden initialises a tag as invisible.
Can shinyjs call my own JavaScript from R?
Yes. The README says the package can also be used to easily call your own custom JavaScript functions from R, which makes it a bridge to arbitrary client-side code rather than a closed set of operations.
Which other Shiny packages are part of the same ecosystem?
shinyalert for popup modals, shinyscreenshot for capturing pages, timevis for timelines, shinycssloaders for loading animations, colourpicker for colours, shinybrowser for browser information and shinydisconnect for disconnect messages, with shinytip, shinymixpanel and shinyforms listed as work in progress.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/daattali-shinyjs)Was this useful?