shiny widget and itable problem (table not extending to show all rows)
I have my MVE code here
import pandas as pd
import numpy as np
from shiny import App, ui, render, reactive
from shinywidgets import output_widget, render_widget, reactive_read
from itables.widget import ITable
# Generate sample data with 10 rows
np.random.seed(42) # For reproducibility
descriptions = [
"This is a very long description that needs to wrap across multiple lines to be readable in the table.",
"Another long text that demonstrates the need for proper column width settings and text wrapping capabilities.",
"The third description with enough content to show how text wrapping works in DataTables with proper configuration.",
"When setting up tables with long text content, it's important to configure the column widths appropriately.",
"Text wrapping is essential for maintaining readability while efficiently using the available screen space.",
]
# Create a DataFrame with 10 rows
data = []
for i in range(1, 11):
data.append(
{
"ID": i,
"Title": f"Item {i}",
"Category": np.random.choice(["Product", "Service", "Resource", "Tool"]),
"Price": round(np.random.uniform(10, 1000), 2),
"Description": descriptions[i % len(descriptions)],
}
)
df = pd.DataFrame(data)
# Define UI
app_ui = ui.page_fluid(
ui.h1("ITables Widget Example"),
ui.p("This example shows the use of ITable widget with Shiny output_widget"),
# Add custom CSS for styling the table
ui.HTML("""
<style>
/* Control text wrapping */
.dataTable td {
white-space: normal !important;
word-wrap: break-word;
max-width: 0; /* Important for text wrapping */
}
/* Improve table appearance */
.dataTable {
border-collapse: collapse;
width: 100%;
}
.dataTable th, .dataTable td {
padding: 8px;
border: 1px solid #ddd;
}
/* Optional: Add some hover effect */
.dataTable tr:hover {
background-color: #f5f5f5;
}
</style>"""),
# Add a dropdown to select rows
ui.input_select(
"row_selection",
"Select rows:",
{"none": "None", "even": "Even rows", "odd": "Odd rows", "all": "All rows"},
),
# Output widget placeholder
output_widget("my_table"),
# Display selected rows
ui.output_text("selected_rows_info"),
)
# Define server
def server(input, output, session):
@render_widget
def my_table():
return ITable(
df,
caption="Sample Data with ITable Widget",
select=True,
columnDefs=[
{"width": "5%", "targets": 0},
{"width": "15%", "targets": 1},
{"width": "10%", "targets": 2},
{"width": "10%", "targets": 3},
{"width": "60%", "targets": 4},
],
style="table-layout:fixed; width:100%;",
)
@reactive.effect
def _():
# Update the widget based on selection
selection = input.row_selection()
if selection == "none":
selected_rows = []
elif selection == "even":
selected_rows = [i for i in range(len(df)) if (i + 1) % 2 == 0]
elif selection == "odd":
selected_rows = [i for i in range(len(df)) if (i + 1) % 2 == 1]
else: # all
selected_rows = list(range(len(df)))
my_table.widget.update(selected_rows=selected_rows)
@render.text
def selected_rows_info():
rows = reactive_read(my_table.widget, "selected_rows")
if not rows:
return "No rows selected"
return f"Selected rows: {rows}"
# Create the Shiny app
app = App(app_ui, server)
the rows at the bottom are cut
my itables are 2.2.5, shiny is 1.3 and shinywigets 0.5.1
The difference between my example and docs is that I am using shiny core with render widget vs shiny express https://mwouts.github.io/itables/shiny.html
Thank you @danieltomasz for testing and reporting! Very nice example, and I confirm that I can reproduce the issue in the Shiny app.
Since that version actually uses the Jupyter widget I also tried to provide the same inputs in Jupyter but there the table seemed to work fine.
Now when I look at the HTML generated by the Shiny app it seems that there is a wrapper around the table that has "only 400px height":
while the table itself has a height of 502px:
At the moment I am not sure of where the 400px height comes from, nor how to investigate this. We might ask for help on the datatables forum as this seems to happen on a div that belongs to datatables, but for that we would need to deploy an example app for them to give a look.
Does itables supports Pyodide? Edit: I will try to rewrite my example as quarto html, maybe it will be enough
hi @mwouts, a session of assertive debuging with Claude (until I pasted the html of the generated webpage, it was giving me halucinated advices) solved this problem for me:
Looking at the HTML source, I can see that your application is properly set up with the necessary widget infrastructure, including the ipywidget-output-binding that Shiny uses to display the ITable widget. This confirms my suspicion that we're dealing with an iframe sizing issue. When AnyWidget (which ITable uses) renders in Shiny, it creates an iframe that needs explicit height management. Root Cause The issue is that the iframe containing the ITable widget isn't properly adjusting its height to the content. Even though we're styling the containers, the iframe itself is constraining the content. Solution: Target the iframe directly Add this CSS to directly target the iframe:
ui.HTML("""
<style>
/* Target the iframe that contains the widget */
.shiny-ipywidget-output iframe {
min-height: 800px !important;
height: auto !important;
}
/* Add !important to override any inline styles */
#my_table, #my_table iframe {
min-height: 800px !important;
}
</style>
"""),
Might be related to https://github.com/mwouts/itables/issues/275 as well?
I can reproduce the issue but I don't see what causes it exactly. I have reached out to the Shiny developers at https://github.com/posit-dev/py-shinywidgets/issues/199, hopefully they will be able to point us in the right direction.
@cpsievert very kindly came with a workaround, which is to create the output widget with a fillable=False argument, like this: output_widget("my_table", fillable=False). That works on my MRE and seemingly on your example too - can you give it a try? Thank you!
Closing as the workaround is now in the docs, but I will follow-up with #406 later on
thanks for working on this, I didnt have time to follow up but everything seems to work! :)
thanks for working on this, I didnt have time to follow up but everything seems to work! :)
You're very welcome, thanks for reporting the issue too!