Version 6.3 Released!

Click to checkout the new features

Release Notes

Dependency Management

This release sees a significant update to how dependencies are managed by the table, with the introduction of the new Dependency Registry, Tabulator will now allow you to register dependant libraries directly with your table, allowing you more control over package importing.

The core of Tabulator, and the vast majority of its functionality has zero depencncies, and this has not changed, and will NEVER change. This means you can set up the vast majority of tables without needing to include any other libraries in your project.

But there are a few occasions where a feature of the table may be reliant on an external dependency. In the past Tabulator required you to set these up on the global variables that the libraries usually require. This option is still available, and existing Table setups will continue to function un interrupted.

Script Tags

You can continue to import your dependency via script tags that will set it up as a global property on the window object. Tabulator knows where to find these and can load them in without any additional setup

<script type="text/javascript" src="https://my-dependency.com/dependency.js"></script>

Just make sure to include this script tag before you instantiate your Tabulator instance. Otherwise the functionality from the dependency will not be there when the table loads.

Setup Option

But you now also have the option to import the library into your project via an import or require statement.

import {MyDependency} from dependency

And then register the library with Tabulator with the dependencies object in the table setup options:

var table = new Tabulator("#example-table", {
    dependencies:{
        "ThatDependency":MyDependency,
    },  
});

This allows much greater flexibility and control over how dependencies are handled in your projects.

The key used to reigster the dependency will depend on the library used. In most cases it should be the varaible name used by the library when it is set on the window object. This is covered in more detail on a case by case basis for each dependency below.

Sheet JS

The SheetJS Library is required to export and import Excel spreadsheets from the table. It can be registered with Tabulator in one of two ways

Script Tags

You can import the library via script tags that will set it up as a global property on the window object. Tabulator knows where to find these and can load them in without any additional setup

<script type="text/javascript" src="https://oss.sheetjs.com/sheetjs/xlsx.full.min.js"></script>

Just make sure to include this script tag before you instantiate your Tabulator instance. Otherwise the functionality from the dependency will not be there when the table loads.

Setup Option

You can also choose to add the library to your project from npm and then import the library into your code via an import statement.

import * as XLSX from 'xlsx';

And then register the library with Tabulator with the dependencies object in the table setup options, this must be done against the XLSX key:

var table = new Tabulator("#example-table", {
    dependencies:{
        XLSX:XLSX,
    },  
});

JS PDF

The jsPDF Library is required to export PDF documents from the table. It can be registered with Tabulator in one of two ways. When using this library you wil also need to include the jsPDF-AutoTable Plugin as this adds the functionality needed to jsPDF to easily tender tables.

Script Tags

You can import the library via script tags that will set it up as a global property on the window object. Tabulator knows where to find these and can load them in without any additional setup

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.20/jspdf.plugin.autotable.min.js"></script>

Just make sure to include these script tags before you instantiate your Tabulator instance. Otherwise the functionality from the dependency will not be there when the table loads.

Setup Option

You can also choose to add the library to your project from npm and then import the library into your code via an import statment. You will then need to apply the plugin to jsPDF before you register it with the table

import jsPDF from 'jspdf'
import { applyPlugin } from 'jspdf-autotable'
applyPlugin(jsPDF)

You should then register the library with Tabulator with the dependencies object in the table setup options, this must be done against the jspdf key:

var table = new Tabulator("#example-table", {
    dependencies:{
        jspdf:jsPDF,
    },  
});

Luxon

The luxon.js is required to manipulate dates and times, the library is used in several formatters, sorters and editors. It can be registered with Tabulator in one of two ways

Script Tags

You can import the library via script tags that will set it up as a global property on the window object. Tabulator knows where to find these and can load them in without any additional setup

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/luxon@2.3.1/build/global/luxon.min.js"></script>

Just make sure to include this script tag before you instantiate your Tabulator instance. Otherwise the functionality from the dependency will not be there when the table loads.

Setup Option

You can also choose to add the library to your project from npm and then import the library into your code via an import statement.

import { DateTime } from "luxon";

And then register the library with Tabulator with the dependencies object in the table setup options, this must be done against the DateTime key:

var table = new Tabulator("#example-table", {
    dependencies:{
        DateTime:DateTime,
    },  
});

Importing

Header Transforms

When importing data from a file, it can some times be useful to be able to transform the incomming column header names.

This can be done using the importHeaderTransform option, this fuction is called on each column header value from the incomming file and can be used to transform these values.

This option takes a function with two arguments. The first argument is the value of the column header, the second argument is an array of all column header values. The function must return the new header value.

In the example below we will use the importHeaderTransform option to trim the incomming column header values to remove all unessisary spaces, and covert them all to lowercase:

//define some array data
//define table
var table = new Tabulator("#example-table", {
    importHeaderTransform:function(header, headers){
        //header - the value of the header to be transformed
        //headers - an array of all header values

        return header.trim().toLowerCase(); //removed unneeded space from header text and conver to lower case
    },   
});

Value Transforms

When importing data from a file, it can some times be useful to be able to transform the incomming cell values.

This can be done using the importValueTransform option, this fuction is called on cell value from the incomming file. This transform occurs befor mutators are triggered and can be used to perform general transofrmations on the whole dataset, such as handling nulll values or JSON decoding

This option takes a function with two arguments. The first argument is the value of the cell, the second argument is an array of all values in the row. The function must return the new cell value.

In the example below we will use the importValueTransform option to JSON decode cell values:

//define some array data
//define table
var table = new Tabulator("#example-table", {
    importValueTransform:function(value, rowData){
        //value - the cell value to be transformed
        //rowData - an array of all values in the row

        return JSON.parse(value); //JSON decode the cells value
    },   
});

Validate Import

Validate File

There are times where you may want to validate a file before importing it into the table, such as checking its size. The importFileValidator option allows you to check the parsed file contents before it is loaded into the table.

The importFileValidator takes a callback with one argument, the file about to be imported. The function should return a value of true if the data is valid, any other value will be considered a validation failure and will cause the import to be aborded and an importError event to be fired, with the response from the validator passed to the event

//define table
var table = new Tabulator("#example-table", {
    importFileValidator:function(data){
         return file.size > 500000 ? "File Too Big" : true; //abort the import if the file is bigger that 500kb
    },  
});

// Trigger an alert with the error message if the import fails
table.on("importError", function(err) {
    alert(err);
})

Validate Data

There are times where you may want to validate the data from a file before importing it into the table. The importDataValidator option allows you to check the parsed data before it is loaded into the table.

The importDataValidator takes a callback with one argument, an array of row data objects from the data parsed from the file. The function should return a value of true if the data is valid, any other value will be considered a validation failure and will cause the import to be aborded and an importError event to be fired, with the response from the validator passed to the event

//define table
var table = new Tabulator("#example-table", {
    importDataValidator:function(data){
        return data.length > 5000 ? "Too Much Data" : true; //abort the import if there are more than 5000 rows
    },  
});

// Trigger an alert with the error message if the import fails
table.on("importError", function(err) {
    alert(err);
})

Editing

Adaptable Editor

The adaptable editor is a bit of a special case, instead of creating an editor itself, it lets you pick between any existing editor based on the value of the cell. This is particularly useful when a column might have varying types of data that you may need each cell to be editied differently.

{title:"Example", field:"example", editor:"adaptable"}

By default the adaptable editor will attempt to pick an editor based on the cells value:

  • Number - If the value is a number type, the number editor will be used
  • Boolean - If the value is a boolean type, the tickCross editor will be used
  • Text - If the value is a string with a carriage return in it, the textarea editor will be used
  • Input - for all other values, the input editor will be used

Note This editor should not be used as a header filter, as header filters have no initial value, it will always default to an input editor if used in this way.

Customise Editor Lookup

You can customise which editors are chosen using the editorLookup option on the editorParams object. This option takes a function with one argument, the CellComponent for the cell being edited. The function should return the choice of editor, this can be any value that can be passed to the normal editor option

{title:"Example", field:"example", editor:"adaptable", editorParams:{
    editorLookup:function(cell){
        //cell - the Cell Component for the cell being edited
        
        var value = cell.getValue();
        
        return Array.isArray(value) ? "list" : "input"; // if the cell contains an array, use the list editor, otherwise use the input editor;
    }
}}

Params Lookup

You can also customise the params that are passed into the chosen editor by using the paramsLookup option on the editorParams object. You should pass an object into this option, with a key for each type of editor that can be looked up, and a value of ts params object:

{title:"Example", field:"example", editor:"adaptable", editorParams:{
    paramsLookup:{
        "input":{
            mask:"AAA-999",
        },
        "number":{
            min:0,
            max:100,
            step:10
        }
    }
}}

Alternatively, if you need more control of the params generated for the editor, you can pass a function into the paramsLookup option. This function takes two arguments, the first ist the editor that has been chosen, the second is the CellComponent for the cell being edited. The function should return the params object for that editor:

{title:"Example", field:"example", editor:"adaptable", editorParams:{
    paramsLookup:(lookup, cell) => {
        return {
            max: cell.getColumn().getField() === "age" ? 100 : 999, //set the max value on the age number editor to 100 and let all other columns use 999
        };
    }
}}

List Editor Values Lookup

The list editor has been updated so when the valuesLookup param has a value of true and the multiselect param is enabled, the value list will now extract the values containined in the cell value arrays rather than the arrays themselves

So when a column is setup to use valuesLookup and multiselect:

{title:"Example", field:"example", editor:"list", editorParams:{
    valuesLookup: true,
    multiselect: true,
}}

Row data with cells that contain arrays of values:

[
    {example:["red", "green"]},
    {example:["green", "blue"]},
    {example:["red", "blue"]},
]

Will now be correctly interpreted as containing multiple values and the values list will be built as a list of unique values from all of these arrays. In this case it will have three items, "red", "green" and "blue".

Formatting

Array Formatter

The array formatter joins arrays of values into a string seperated by a delimiter character ("," by default)

{title:"Example", field:"example", formatter:"array", formatterParams:{
    delimiter: "|", //join values using the "|" delimiter
    valueMap: "age", //show the age property of the objects
}}

The formatter has optional properties for the formatterParams object:

  • delimiter - the character used to join the array values togeather (default "|")
  • valueMap - used when the array contains objects with nested properties to choose a property to display

Value Maps

Sometimes the array could be storing a series of objects with nested properties. you can use the valueMap param to choose which property should be displayed for each item in the array

In this example lets assume we have a cell that for each row contains array of people objects with the following values:

[
    {
       id:12345,
        details:{
            name:"bob",
            age:32,
            height:45,
        }
    },
    {
        id:25142,
        details:{
            name:"jim",
            age:52,
            height:145,
        }
    }
]

And lets say we wanted to show the name of each person in that array, We could use tha valueMap to choose the property we wanted to display. In this case we can pass a string in to select the nested property we are looking for using standard dot notation. this will use the tables nestedFieldSeparator option for whatever your default separator is.

{title:"Example", field:"example", formatter:"array", formatterParams:{
    delimiter: "|", //join values using the "|" delimiter
    valueMap:"details.name", //show the name of each item in the array
}}

You can also choose to pass a callback function into the valueMap param. This callback should be compatible with the standard js array map function. it should have one argument, the incoming array item to be mapped, and should return the mapped value for that item.

{title:"Example", field:"example", formatter:"array", formatterParams:{
    valueMap:function(item){
        return item.details.name; //show the name property in the details object on each item in the array
    }), 
}}

JSON

The json formatter uses the JSON.stringify function to pretty print objects and arrays

{title:"Example", field:"example", variableHeight:true, formatter:"json", formatterParams:{
    multiline: false, //show output on only one line
    indent: " ", //indent object properties with a single spave
    replacer: ["cheese"] //show only the "cheese" property from the cell value object
}}

The formatter has optional properties for the formatterParams object:

  • multiline - pretty print the output on multiple lines (default true)
  • indent - the indent character used for object properties (default "\t")
  • replacer - the replacer argument for the JSON.stringify function. Checkout the MDN Docs for full details

Note - When using this formatter in multiline mode, you should also set the variableHeight option on the column definition to true, this will ensure the row height is recalculated if the resizing of the column causes text to wrap

Adaptable Formatter

The adaptable formatter is a bit of a special case, instead of creating a formatter itself, it lets you pick between any existing formatter based on the value of the cell. This is particularly useful when a column might have varying types of data that you may need each cell to be formatted differently.

{title:"Example", field:"example", formatter:"adaptable"}

By default the adaptable formatter will attempt to pick a formatter based on the cells value:

  • Boolean - If the value is a boolean type, the tickCross formatter will be used
  • Text - If the value is a string with a carriage return in it, the textarea formatter will be used
  • Plain Text - for all other values, the plaintext formatter will be used

Customise Formatter Lookup

You can customise which formatters are chosen using the formatterLookup option on the formatterParams object. This option takes a function with one argument, the CellComponent for the cell being edited. The function should return the choice of formatter, this can be any value that can be passed to the normal formatter option

{title:"Example", field:"example", formatter:"adaptable", formatterParams:{
    formatterLookup:function(cell){
        //cell - the Cell Component for the cell being formatted
        
        var value = cell.getValue();
        
        return typeof === "boolean" ? "tickCross" : "plaintext"; // if the cell contains a boolean user the tickCross formatter, otherwise use the plaintext formatter;
    }
}}

Params Lookup

You can also customise the params that are passed into the chosen formatter by using the paramsLookup option on the formatterParams object. You should pass an object into this option, with a key for each type of formatter that can be looked up, and a value of ts params object:

{title:"Example", field:"example", formatter:"adaptable", formatterParams:{
    paramsLookup:{
        "tickCross":{
            tickElement:"YES!",
        }
    }
}}

Alternatively, if you need more control of the params generated for the formatter, you can pass a function into the paramsLookup option. This function takes two arguments, the first ist the formatter that has been chosen, the second is the CellComponent for the cell being edited. The function should return the params object for that formatter:

{title:"Example", field:"example", formatter:"adaptable", formatterParams:{
    paramsLookup:(lookup, cell) => {
        return {
            tickCross: cell.getColumn().getField() === "sad" ? ":(" : ":)", //set the tick value to :( if the field is sad, otherwise set it to :)
        };
    }
}}

Sorting

Array Sorter

The array has been updated to add a couple of new features

The new string sort type, allows the sorter to join an array of strings togeather in an array and then perform a string comparison with the next row.

This would help in scenarios where a cell's value is an array of strings, such as:

["Steve", "Bob", "Jim"]

This could then be sorted with the following sorter setup

{title:"Example", field:"example", sorter:"array", sorterParams:{
    type:"string",
}}

Value Maps

The new valueMap param can be used in the instance where an array could be storing a series of objects with nested properties. It is used to choose which property should be used for each item in the array to perform the sort

In this example lets assume we have a column that for each cell contains array of people objects with the following values:

[
    {
        name:"bob",
        details:{
            age:32,
            height:45,
        }
    },
    {
        name:"jim",
        details:{
            age:52,
            height:145,
        }
    }
]

And lets say we wanted to sort the column by the max age of any person in that array, We could use tha valueMap to choose the property that the array sorter sorts by. In this case we can pass a string in to select the nested property we are looking for using standard dot notation. this will use the tables nestedFieldSeparator option for whatever your default separator is.

{title:"Example", field:"example", sorter:"array", sorterParams:{
    type:"max", //sort by they highest value from each item in the array
    valueMap:"details.age", //sort by the age property in the details object on each item in the array
}}

You can also choose to pass a callback function into the valueMap param. This callback should be compatible with the standard js array map function. it should have one argument, the incoming array item to be mapped, and should return the mapped value for that item.

{title:"Example", field:"example", sorter:"array", sorterParams:{
    type:"max", //sort by they highest value from each item in the array
    valueMap:function(item){
        return item.details.age;
    }), //sort by the age property in the details object on each item in the array
}}

Mutate

Import Mutators

You can use the mutatorImport and mutatorImportParams options on a column definition to alter the value of data in a column as it is imported into the table.

The example below will transform all ages into a boolean, showing if they are over 18 or not. The mutatorImportParams is used to pass the age limit to the mutator so the same mutator function can be used on multiple columns with different age limits:

var ageMutator = function(value, data, type, params, column){
    return value >= params.legalAge;
}

{title:"Under Age", field:"age", mutatorImport:ageMutator, mutatorImportParams:{legalAge:18} }

Note: The mutatorImport only works if you have columns defined on your table, if you are using the autocolumns option then the columns do not exist when the data is imported, for this scenario look at using the importTransform option inestead

Pagination

Page Out of Range Behaviour

When loading paginated data, if the current page shown is larger thant the max page, Tabulator will just continue to show the data presented to it, to minimize the disruption to the user.

If you would prefer to force the behaviour in this instance, you can use the "paginationOutOfRange" option.

var table = new Tabulator("#example-table", {
    pagination:true, //enable pagination
    paginationOutOfRange:"last", //show the last page if pagination is out of range
});

The paginationOutOfRange option takes any of the standard setPage values, this can either be an integer representing the page or there are also four strings that you can pass into the parameter for special functions.

  • "first" - show the first page
  • "prev" - show the previous page
  • "next" - show the next page
  • "last" - show the last page

You can alternatively pass a callback to this function to decide what to do in this scenario, the callback should take two arguments, the first is the current page number, the second is the maximum page number. It should return the page that should be loaded, this can either be am integer or one of the strings outlined above

var table = new Tabulator("#example-table", {
    pagination:true, //enable pagination
    paginationOutOfRange:function(currentPage, maxPage){
        //currentPage - the current page number
        //maxPage - the maximum page number

        return currentPage > 10 ? "first" : "last";
    }
});

Range Selection

Range Auto Focus

By default, when you select a range that consists of one cell, it will automatically gain focus. There are some scenarios in which this is undesirable. The autofocus functionality can be disabled using the selectableRangeAutoFocus option:

var table = new Tabulator("#example-table", {
  selectableRangeAutoFocus:false, //disable auto focus on cell during range selection
});

Bug Fixes

v6.3.0 Release

The following minor updates and bugfixes have been made:

  • The loading alert is now correctly shown when importing data into the table
  • Cells using the textarea formatter will no longer render excessivly tall
  • Scrolling to focused cell now works correctly when spreadsheet mode has been enabled
  • Fixed issue with spreadsheet ranges being corruped after arrow key press

Donate