Example: Excel download through context menu (not csv but xlsx)
I wanted to share the method I use for downloading reactable to excel. Right-click on the table to bring up the context menu.

shiny app
library(shiny)
library(reactable)
ui <- fluidPage(
tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.6/xlsx.mini.min.js"), # excel export library
includeScript(path = "app.js"),
includeCSS(path = "app.css"),
reactableOutput("test")
)
server <- function(input, output, session) {
output$test <- renderReactable(
reactable(
data = iris
)
)
}
shinyApp(ui, server)
app.js
document.addEventListener("contextmenu", function (event) {
try {
if (event.target.closest(".reactable") != null) {
event.preventDefault();
let id = event.target.closest(".reactable").id;
let menu = document.createElement("div");
menu.classList.add("context_menu");
menu.style = `top:${event.pageY-5-window.pageYOffset}px;left:${event.pageX-5-window.pageXOffset}px`;
menu.onmouseleave = function() { menu.outerHTML = ''; };
menu.innerHTML = ("<div onclick ='JS_reactable_excel_download(\"" + id + "\")'>Excel Download</div>");
document.body.appendChild(menu);
}
} catch {};
},false);
function JS_reactable_excel_download(id) {
var json = Reactable.getInstance(id).preGroupedRows.map(row => row.original);
for (let row = 0; row < json.length; row++) {
for (key of Object.keys(json[row])) {
try {
json[row][key] = json[row][key].replace(/<\/?[^>]+>/gi, ''); // Remove html tag if included
} catch {};
}
}
var ws = XLSX.utils.json_to_sheet(json);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
XLSX.writeFile(wb, id+'.xlsx');
}
css
.context_menu {
position: fixed;
background: #fff;
color: #333;
cursor: pointer;
padding: 5px 0px;
border: 1px solid #ccc;
box-shadow: rgba(0, 0, 0, 0.5) 2.4px 2.4px 3.2px;
z-index: 111;
}
.context_menu > div {
padding: 4px 20px;
margin: 0;
font-size: 12px;
}
.context_menu > div:hover {
background: #edeeee;
}
That's pretty cool, thanks for sharing! I didn't know about the xlsx library (or really SheetJS). It looks like a lightweight library for creating XLSX files which would definitely be useful to a lot of people. I might adapt a simplified version of this for an example at some point.
And also FYI, this is using some undocumented reactable APIs that may change without notice in the future. But I can see how preGroupedRows would be useful for cases like this, so that could be a publicly supported state property in the future.
Yes. In fact, there seem to be a few more undocumented functions, but they don't seem official, so I only referred to the pregroupedrows used in your csv conversion logic.