Tabulator with variable height

Tabulator is a great component.
It’s blistering fast when the height is set to a fix amount (eg ‘500px’).
Because tabulator automatically optimizes memory with a fixed height.

So we’d like to keep the speed.
But the fixed height is a problem in most practical cases.
What we need is a Tabulator that scales along with it’s parent but that stays blistering fast.

Also according to the tabulator js docs, you can ‘manage’ preloading by providing a ‘renderVerticalBuffer

But it doesn’t seem to work

fixed height of 500px

when rescaling:

When rescaling the window (or any standard html.Div) the table height should rescale automatically (ie. pagination should stay visible)
Like in this badly photoshopped examlpe

So Setting
maxHeight=“100%”,
renderVerticalBuffer=50,
should resolve this, but it doesn’t work…

Probably something trivial for someone who knows what he is doing.
Kinda stuck on this…

import numpy as np
import pandas as pd

import dash
from dash import html, dcc
import dash_tabulator


df = pd.DataFrame(np.random.randint(0,100,size=(1000, 4)), columns=list('ABCD'))
tabulator_columns = [{"title": x,
                      "field": x,
                      } for x in df.columns
                     ]
# Set tabulator fix-height via tabulator options to 
tabulator_options = dict(
    # 1 - Works as expected but impossible to resize dynamically
    height="500px",  
    
    # 2 - Doesn't work. Same as simple 100%
    #maxHeight="100%",        
    #renderVerticalBuffer=50,
    
    # 3 - Doesn't work.
    #height="calc(100%-10px)",  

    pagination="local",
    paginationSize=100,
    paginationSizeSelector=[10,50,200,500,True],
    frozenRows=1,
    )

df['id']=df.index
data = list(df.T.to_dict().values())

tabulator = dash_tabulator.DashTabulator(
    id      = 'tabulator',
    data    = data,    
    columns = tabulator_columns,
    options = tabulator_options,
    theme   = "tabulator",
    )

external_scripts = ['https://oss.sheetjs.com/sheetjs/xlsx.full.min.js']
external_stylesheets = ['https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css',
                        'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css']
app = dash.Dash(__name__, external_scripts=external_scripts, external_stylesheets=external_stylesheets)
app.layout = html.Div([
    tabulator
    ], style={'width':'100%', 'max-height':'100%', 'overflow':'auto'})

if __name__ == '__main__':
    app.run_server(debug=True)

Hello @popo,

Have you tried using 100vh instead of trying 100%? I’ve noticed, especially with tables, how % doesnt play as well as vh.

If that doesnt work, then you’ll need to add an eventlistener for window resize that will trigger a clientside_callback to update the tabulator options.

Thanks jinnyzor but 100vh scales the table to the viewport height.

So what if the tabulator finds itself in any div of the page eg in some collapsible card or something?

I went on trying to use JS…as this is a very important thing to me (and I think everyone using tabulators)
although it really feels like over-complicating things…

The idea (I guess) is to set the height to eg 80vh that triggers a tabulator ‘renderComplete’ event with a callback that calculates the correct vertical size of the tabulator.

But this does not work. My understanding of javascript is insufficient.

in python

...
from dash_extensions.javascript import Namespace
...

ns = Namespace("myNamespace", "tabulator")

...

main_tabulator = dash_tabulator.DashTabulator(
    id=id,
    columns=columns,
    data=data,
    options=dict(layout="fitDataStretch",
                            height="80vh",
                            pagination="local",
                            paginationSize=50,
                            paginationSizeSelector=[5,10,20,50,100,250,500, True],
                            paginationCounter = 'rows',

                            renderComplete = ns("renderComplete")
                           ),
                   )
app.layout = html.Div([main_tabulator],
                                  fluid=True,
                                  style={
                                      #'overflow':'auto',                                      
                                      'height':'100%'
                                    }
                                  )

in assest/tabulator_verticalsizing_causes_severe_headaches.js

window.myNamespace = Object.assign({}, window.myNamespace, {
    tabulator: {
        renderComplete: function ()
                        {
                            const tabulator = this;
                            const table = tabulator.element;
                            const rowsContainer = table.querySelector('.tabulator-tableHolder');
                           if (
                                table.clientHeight === 0 || // Table is hidden we can't calculate the height
                                rowsContainer.scrollHeight > rowsContainer.clientHeight  // Scroll bar is present, leave height as is
                           )
                            {
                                console.log( table.clientHeight === 0 ? 'Table not visible' : 'No need to shrink' );
                                return;
                            }

                            const height = table.querySelector('.tabulator-header').clientHeight +
                                table.querySelector('.tabulator-table').clientHeight - 50;
                            

                            console.log(`Shrinking table to ${height}px`);

                            tabulator.setHeight(`${height}px`);
                        },
               }
     });

And, even if it would work, 80vh only triggers the event when the viewport changes.
If the tabulator would be in a div that scales independently from the main viewport, nothing would happen.

How do we achieve something as trivial as having the tabulator automatically scale to the height of it’s container?

Thanks in advance.

Here, add this to your style sheet:

div:has(div.tabulator) {
    height: 100%;
    width: 100%;
    overflow: hidden;
}

Then you can use percentages just like normal. :slight_smile: