R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
139: Custom JavaScript Integration in Shiny
I've seen this exact scenario play out a dozen times. You want your Shiny app to do something that R just isn't built for—like listening for a specific browser event or manipulating the DOM in real-time—so you write a bit of JavaScript. You put it in your UI, you call it from your server, and then... nothing happens. No error in the R console, but the app just sits there.
Take a look at this snippet. The goal here is to trigger an R message whenever the user resizes their browser window.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
tags$script("
window.onresize = function() {
var width = window.innerWidth;
console.log('Window resized to: ' + width);
// I want R to know the width changed!
resizeEvent = width;
};
"),
textOutput("resize_text")
)
server <- function(input, output) {
observeEvent(input$resizeEvent, {
output$resize_text <- renderText({
paste("The JS told me the width is now:", input$resizeEvent)
})
})
}
shinyApp(ui, server)
The "Invisible" Variable Problem
If you run this, you'll see the width updating in your browser's developer console, but the R output will stay blank. Why? Because you've created a JavaScript variable called resizeEvent, but you haven't actually told Shiny to send that value across the network to the R session.
In a standard JS project, variables just exist in memory. But Shiny is a client-server architecture. The JavaScript is running in the user's browser (the client), and the R code is running on a server. They are separated by a network boundary. Simply assigning a value to a variable in JS doesn't magically teleport that value into the R input object.
Bridging the Gap with Shiny.setInputValue
To get data from the browser into R, you have to use a specific Shiny JavaScript API method: Shiny.setInputValue(). This function tells the browser to package the data and send it over the websocket to your R server, where it then appears as an entry in the input list.
Here is the fix. We replace the simple variable assignment with the Shiny API call:
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
tags$script("
window.onresize = function() {
var width = window.innerWidth;
// This is the magic line:
Shiny.setInputValue('resizeEvent', width);
};
"),
textOutput("resize_text")
)
server <- function(input, output) {
# Now input$resizeEvent actually exists!
output$resize_text <- renderText({
req(input$resizeEvent)
paste("The JS told me the width is now:", input$resizeEvent)
})
}
shinyApp(ui, server)
Now, whenever the window resizes, JS fires Shiny.setInputValue('resizeEvent', width). Shiny catches this on the server side, updates input$resizeEvent, and triggers any observeEvent or reactive expression depending on it. I added a req() in the server because input$resizeEvent is NULL until the first resize happens, and we don't want the app to throw an error on startup.
Managing Complexity with External JS Files
Writing JS inside tags$script() is fine for five lines of code, but once you start building actual features, your UI file becomes a nightmare to read. I highly recommend moving your JavaScript into a separate file.
Create a folder named www in your app directory (Shiny looks for this folder by default). Put your code in www/custom_logic.js. Then, in your UI, simply call it using tags$head(tags$script(src = "custom_logic.js")).
This doesn't just clean up the code; it allows you to use a proper IDE with JavaScript syntax highlighting and linting, which will save you from the "missing semicolon" headaches that are so common when embedding scripts in R strings.
📋 Practical Task
Exercise: Implementing a Custom JS "Copy to Clipboard" Button
In this exercise, you will integrate a custom JavaScript function that allows a user to copy a generated string from the Shiny UI to their system clipboard. Since R cannot access the user's system clipboard directly via the browser, you must bridge the two using JavaScript.
Requirements:
- Create a Shiny app with a
textInputwhere the user can type something. - Add an
actionButtonlabeled "Copy to Clipboard". - Write a JavaScript function (either in
tags$scriptor awwwfile) that uses thenavigator.clipboard.writeText()API to copy the content of the text input. - The Twist: After the JavaScript successfully copies the text, it must use
Shiny.setInputValue()to notify the R server that the copy operation was successful. - The R server should then display a temporary "Copied!" message in the UI using
showNotification().
There are no comments for now.