Create synchronized, interactive dashboards where one click updates multiple components
linkeR makes it effortless to create linked views in
‘shiny’ applications. When users interact with one component (like
clicking a map marker), all related components (tables, charts, other
maps) automatically update to show corresponding information.
# Complex manual setup for each component pair
observeEvent(input$map_marker_click, {
  clicked_id <- input$map_marker_click$id
  # Find corresponding table row
  row_idx <- which(my_data()$id == clicked_id)
  # Update table selection
  dataTableProxy("my_table") %>% selectRows(row_idx)
  # Update map view
  leafletProxy("my_map") %>% setView(...)
  # Update any other components...
  # Repeat this for every component combination!
})
observeEvent(input$my_table_rows_selected, {
  # More boilerplate code...
  # Handle edge cases...
  # Ensure consistency...
})# One line links everything!
link_plots(
  session,
  my_map = my_data,
  my_table = my_data,
  shared_id_column = "id"
)| Manual Approach | linkeR Approach | 
|---|---|
| 50+ lines of observer code | 1 function call | 
| Easy to introduce bugs | Tested and reliable | 
| Hard to maintain | Declarative and clear | 
| Limited to 2 components | Unlimited components | 
| No built-in customization | Rich customization options | 
# Install from CRAN (when available)
install.packages("linkeR")
# Or install development version from GitHub
# install.packages("devtools")
devtools::install_github("EpiForeSITE/linkeR")For linking to work, your setup needs:
layerId = ~your_id_columnreactive()# Good: Proper setup
my_data <- reactive({
  data.frame(
    id = 1:10,           # ← Shared ID column
    name = paste("Item", 1:10),
    lat = runif(10), lng = runif(10)
  )
})
output$my_map <- renderLeaflet({
  leaflet(my_data()) %>%
    addMarkers(layerId = ~id)  # ← layerId matches shared_id_column
})
link_plots(session, my_map = my_data, shared_id_column = "id")
# Bad: Missing layerId
output$my_map <- renderLeaflet({
  leaflet(my_data()) %>%
    addMarkers()  # ← No layerId = no linking!
})| Component | Status | Notes | 
|---|---|---|
| Leaflet Maps | ✅ Full Support | Interactive maps with markers, circles, polygons | 
| DT DataTables | ✅ Full Support | Sortable, filterable tables | 
| Plotly Charts | 🔄 Partial | Single selection supported | 
| Custom Components | 🔄 Partial | Any ‘shiny’ component with click events, Requires manual event handling | 
| Base R Plots | 📋 Planned | Static plots with click detection | 
| Mapbox | 📋 Planned | Alternative mapping solution | 
For native plotly selection highlighting to work, your Shiny UI must include a custom JavaScript message handler:
tags$script(HTML("
  Shiny.addCustomMessageHandler('eval', function(code) {
    try {
      eval(code);
    } catch(e) {
      console.error('JavaScript execution error:', e);
    }
  });
"))This enables linkeR to send selection updates to plotly charts for visual feedback.
Contributions are welcome and encouraged! Follow best practice for github contributions.
# Clone and setup
git clone https://github.com/EpiForeSITE/linkeR.git
cd linkeR
# Install dependencies
devtools::install_deps()
# Run tests
devtools::test()
# Check package
devtools::check()This project is licensed under the MIT License - see the LICENSE file for details.