I have been developing a somewhat complicated Shiny application. It presents the user with various tables and lets the user filter, sort and search the tables. For that, I have been using the DT package, which is a wrapper for the DataTables JavaScript library. (Full disclosure: my knowledge of JavaScript is basically limited to being able to type the name "JavaScript".) Until recently, I have had no meaningful issues with using DT. That changed with my current application.
One of the tables in my application contains a substantial number of columns, forcing horizontal scrolling. The right-most columns are mostly date fields, which means the DT filter controls for those columns are sliders (which may or may not be relevant here). I discovered that if you try to use the filter control in one of the columns toward the right, the table spontaneously scrolls itself to the left, before you can set the filter.
You can see the problem by downloading and running a small example I constructed (which includes my workaround, to be described below). Besides R itself, it only requires the Shiny and DT packages. The demo program uses numerical rather than date columns, which is not a concern here. If you try to use a filter in a right-hand column, you will experience the leftward jump. Even stranger, if you then try to set a filter in a left-hand column, the table will spontaneously scroll to the right.
Other than the nature of the data, I tried to mimic in the demo the presentation of the table in my actual application, meaning I used the same options for the call to datatable() to the extent possible. Despite that, there is one significant (and unexplained) difference between the demo and my large application. In the demo, if you scroll back to the column you were trying to filter after the table jumps, the filter control (sliders) is open and waiting to be used. So you can set the filter. In my large application, when you scroll back the filter control is closed ... and if you click on it, you get another jump to the left. So it is not possible to the set the filter without some sort of intervention.
In my example (and in my application), I have included a column visibility control, a standard DT feature. You can circumvent the jumping nonsense by temporarily hiding enough columns that the table does not need horizontal scrollbars. On a table this big, that is rather tedious, which leads to my workaround. There is a select input labeled "Isolate Column". You can use it to temporarily select one column at a time, for purposes of setting the column filter. When you are done setting filters, select "NONE" and the table reverts to displaying whichever columns were visible before you started isolating columns. That brings me to another inexplicable (to me) issue: in my example, the isolated column sits at the left of the table, but in my production code, it sits in the middle.
The implementation of the isolation feature involves adding the select input and an event observer to react to its use. Restoration of the visible columns is done by a table proxy, created via a call to DT::dataTableProxy(). Now comes another oddity. While the table proxy provides a mechanism for selecting which columns are visible, it does not provide a mechanism for determining which columns are currently visible. As a result, I had to add some JavaScript code, attached to the table as a callback, to record the roster of visible columns. Recall that I confessed earlier to my pretty much total ignorance of JavaScript. Fortunately, Posit offers a free AI helper for Shiny, Shiny Assistant, which was able to crank out the code I needed.
This might be a good time to mention that I tried three or four different AI models, including Shiny Assistant, to fix the scrolling problem. They all failed repeatedly, or came up with things that fixed the scrolling but broke something else. Apparently a bunch of things are interacting to create this bug. I'm worried my karma might be one of them.