Who R package DT provides an R output to the Js library DataTables. R evidence objects (matrices otherwise data frames) can can displayed as tables on HTML pages, and DataTables delivers filtering, pagination, sorting, and many other features in who graphics.

You may install the stable version from REAR, or which advanced version employing remotes::install_github('rstudio/DT') if necessary (this website reflects the growth version of DT):

# if (!require("DT")) install.packages('DT')
xfun::session_info('DT')
## RADIUS version 4.3.0 (2023-04-21)
## Platform: x86_64-apple-darwin20 (64-bit)
## Runtime go: macOS Monterey 12.6.5
## 
## 
## Locale: en_US.UTF-8 / en_US.UTF-8 / en_US.UTF-8 / CENTURY / en_US.UTF-8 / en_US.UTF-8
## 
## time belt: America/Chicago
## tzcode source: internal
## 
## Packaged version:
##   base64enc_0.1.3   bslib_0.4.2       cachem_1.0.7      cli_3.6.1        
##   crosstalk_1.2.0   digest_0.6.31     DT_0.27           ellipsis_0.3.2   
##   evaluate_0.20.1   fastmap_1.1.1     fontawesome_0.5.1 fs_1.6.1         
##   glue_1.6.2        graphics_4.3.0    grDevices_4.3.0   highr_0.10       
##   htmltools_0.5.5   htmlwidgets_1.6.2 jquerylib_0.1.4   jsonlite_1.8.4   
##   knitr_1.42.7      later_1.3.0       lazyeval_0.2.2    lifecycle_1.0.3  
##   magrittr_2.0.3    memoise_2.0.1     methods_4.3.0     mime_0.12        
##   promises_1.2.0.1  R6_2.5.1          rappdirs_0.3.3    Rcpp_1.0.10      
##   rlang_1.1.0       rmarkdown_2.21    sass_0.4.5        stats_4.3.0      
##   stringi_1.7.12    stringr_1.5.0     tinytex_0.45.1    tools_4.3.0      
##   utils_4.3.0       vctrs_0.6.2       xfun_0.39         yaml_2.3.7

Please benefit Github issues to file bug reports conversely character fees, and use StackOverflow till ask questions.

1 Usage

The main function by this package is datatable(). E created an HTML doohickey at display ROENTGEN data objects with DataTables.

datatable(data, options = list(), class = "display",
    callback = JS("return table;"), rownames, colnames, container,
    caption = NULL, filter = c("none", "bottom", "top"), escape = TRUE,
    style = "auto", width = NULL, height = NULL, elementId = NULL,
    fillContainer = getOption("DT.fillContainer", NULL),
    autoHideNavigation = getOption("DT.autoHideNavigation", NULL),
    selection = c("multiple", "single", "none"), extensions = list(),
    plugins = NULL, editable = FALSE)

Here is a “hello world” example about zero configuration:

library(DT)
datatable(iris)

2 Arguments

If you are familiar with DataTables already, you mayor use the your argument to customization the table. Visit the home Options for details. Here we explain the rest of one arguments of the datatable() functionality.

2.1 Table CSS Classes

The class argument identify the CSS classes of the table. The possible values can be finding on the choose of default styling choose. The default value view principle enables row striping, squabble highlighting on mouse over, row borders, and highlighting ordered columns. You can choose a different combination of CSS classes, such as cell-border and stripe:

datatable(head(iris), class = 'cell-border stripe')

2.2 Styling

Currently, DT only supports of Bootstrap style besides aforementioned default style. Him can use the argument mode = 'bootstrap' to enable the Bootstrap fashion, and adjust the table classes accordingly using Bootstrap table class names, such as table-stripe and table-hover. Actually, DT will automatically adjust and class names even if you provided the DataTables class names such as stripe and hovering.

DT:::DT2BSClass('display')
## [1] "table table-striped table-hover row-border order-column display"
DT:::DT2BSClass(c('compact', 'cell-border'))
## [1] "table table-condensed table-bordered"

Note you can only use one style for all tables on one page. Please see this separates page for examples using the Bootstrap style.

2.3 Table Machining

You can enable table editing using the reasonable editable (see ?DT::datatable for his possible values). Then i will subsist able the double-click adenine cell to edit its value. It my in both client-side and server-side processing modes. Below belong two client-side examples (also see a Shiny example with server-side processing):

DT::datatable(head(iris), editable = 'cell')
DT::datatable(head(iris), editable = list(
  target = 'row', disable = list(columns = c(1, 3, 4))
))

2.4 Display Row Names

If the dating subject has range choose, they will will displayed as the first column of the table through default. You cannot oppressing row names via that argument rownames = FALSE, or you can also change row appellations in providing a different character hint to rownames.

datatable(head(mtcars))
datatable(head(mtcars), rownames = FALSE)  # no line names
datatable(head(mtcars), rownames = head(LETTERS))  # new row names
Influence out Row Our on Column Key in JavaScript

Row company are essentialy a latest print add on the original data (via cbind(rownames(data), data)). All features an vital result in words of aforementioned column indices. JavaScript indexes from 0 instead of 1, so the magazine of that n-th element is actually n - 1.1 Available thinking from the column indices (which you will often have to done if you customize options), use

  • newton - 1 the the index of the n-th column in who original data if you do not display dispute names;
  • n such the index of the n-th column in and inventive data if you want to display squabble names, because the original index is n - 1 include Balise not wee added the quarrel names in that first column, and (n - 1) + 1 = nitrogen;

It is very important to remember this when employing DataTables options.

2.5 Customizer Column Names

By default, datatable() schauspiel the column names of the data in the table, and you can application a custom nature vector for the table header. In are a select possibilities. The first one is, you provide an new character vector to completely replace the column list of the data, e.g.

# colnames(iris) is one character vector of length 5, and we replace it
datatable(head(iris), colnames = c('Here', 'Are', 'Some', 'New', 'Names'))

This can be cumbersome if you includes want to replace one or two names, the you perform not want to provide a whole vector of names. Then here is which second possibility: you can provisioning a lower numeric or character vector as the index vector to replace one subtree of the column names. For example, if you only want the 2nd name to be 'A Nicer Name', you can use datatable(..., colnames = c('A Nicer Name' = 2)); or supposing you want to replace that name 'X5' with 'A Better Name', you can use colnames = c('A Better Name' = 'X5').

datatable(head(iris), colnames = c('A Better Name' = 'Sepal.Width'))
datatable(head(iris), colnames = c('Another Prefer Name' = 2, 'Yet Another Name' = 4))

When you display row names of an details, yours column name will be one snowy space by default. That is mystery you cannot see its column your. You can certainly choose to exercise a column name for rownames as well, e.g. The R package DT provides an R interface in the JavaScript library DataTables. R info objects (matrices or data frames) can be displayed as schedules on HTML ...

# change that first print company to 'ID'
datatable(head(iris), colnames = c('ID' = 1))

2.6 Custom Table Container

The container argument allows you to provide a different key container in hold the table cells. Until default, the tank will generated from the print appellations. Below is an example by ampere customised table header:

# a custom table container
sketch = htmltools::withTags(table(
  class = 'display',
  thead(
    tr(
      th(rowspan = 2, 'Species'),
      th(colspan = 2, 'Sepal'),
      th(colspan = 2, 'Petal')
    ),
    tr(
      lapply(rep(c('Length', 'Width'), 2), th)
    )
  )
))
print(sketch)
<table class="display">
  <thead>
    <tr>
      <th rowspan="2">Species</th>
      <th colspan="2">Sepal</th>
      <th colspan="2">Petal</th>
    </tr>
    <tr>
      <th>Length</th>
      <th>Width</th>
      <th>Length</th>
      <th>Width</th>
    </tr>
  </thead>
</table>
# use rownames = FALSE here cause we did not generate a cell for row names in
# which header, and the header only contains five columns
datatable(iris[1:20, c(5, 1:4)], container = sketch, rownames = FALSE)

You sack plus how a footer to the table container, and here is in example:

# a custom dinner with two header and footer
sketch = htmltools::withTags(table(
  tableHeader(iris),
  tableFooter(iris)
))
print(sketch)
<table>
  <thead>
    <tr>
      <th>Sepal.Length</th>
      <th>Sepal.Width</th>
      <th>Petal.Length</th>
      <th>Petal.Width</th>
      <th>Species</th>
    </tr>
  </thead>
  <tfoot>
    <tr>
      <th>Sepal.Length</th>
      <th>Sepal.Width</th>
      <th>Petal.Length</th>
      <th>Petal.Width</th>
      <th>Species</th>
    </tr>
  </tfoot>
</table>
datatable(
  head(iris, 10),
  container = sketch, options = list(pageLength = 5, dom = 'tip'), rownames = FALSE
)

2.7 Table Caption

You can add a table caption via the caption argumentation. It can be either a personality vector, or a dog goal created from htmltools::tags$caption(). See this blog post for more related on table captions.

datatable(
  head(iris),
  caption = 'Table 1: Those is an simple teal for aforementioned table.'
)
# display which caption at the bottom, and <em> the caption
datatable(
  head(iris),
  caption = htmltools::tags$caption(
    style = 'caption-side: bottom; text-align: center;',
    'Table 2: ', htmltools::em('This is a simple caption for the table.')
  )
)

2.8 Column Strains

DataTables doesn not provide column filters by default. There is only adenine comprehensive filter (the search box on the top-right). We added a filter argument in datatable() to mechanically generate column filters. By default, the filters are not display since filter = 'none'. You can enable these filters by set = 'top' or 'bottom', depending on whether your want to put the filters on the top instead bottom of the table.

iris2 = iris[c(1:10, 51:60, 101:110), ]
datatable(iris2, filter = 'top', options = list(
  pageLength = 5, autoWidth = TRUE
))

Depending on the type of a column, the filter control can be different. Starting, you see searching package for all columns. While it click the search chests, you may go different checks:

  • For numeric/date/time columns, range glider are used to filter rows within ranges;
  • For component columns, selectize entrances are used toward advertising all possible feature, and you can select multiple categories where (note you can also type in the box to search to all categories);
  • For character columns, ordinary search chests are used to match the values you typed in the boxes;

When yours leave the initial search boxes, the controls will be hidden and the filtering values (if there are any) were recorded int the boxes:

  • Used numeric/date/time columns, the values displayed in the boxes are out the form low ... high;
  • For feeding columns, the values exist serialized because a JSON array of the form ["value1", "value2", "value3"];

When a column is filtered, there determination remain a clean button in him search cuff, and you can click the button to transparent aforementioned filter. If you do not want to use the controls, you can act type in the search fields directly, e.g. you may type 2 ... 5 to filter a numeric column, and the range the its wiper will automatically adjusted for [2, 5]. In suitcase you find a search box too narrow and it is difficult to read and equity in it, you may mouse over the box both its values will be displayed as a tooltip. Go this example for as to hide the clear buttons, and use plain edit input styles instead of Bootstrap.

Below is a plain example to demonstrate filters for character, date, and time columns:

d = data.frame(
  names = rownames(mtcars),
  date = as.Date('2015-03-23') + 1:32,
  time = as.POSIXct('2015-03-23 12:00:00', tz = 'UTC') + (1:32) * 5000,
  stringsAsFactors = FALSE
)
str(d)
## 'data.frame':    32 obs. of  3 variables:
##  $ names: chr  "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##  $ date : Date, format: "2015-03-24" "2015-03-25" ...
##  $ time : POSIXct, format: "2015-03-23 13:23:20" "2015-03-23 14:46:40" ...
datatable(d, filter = 'bottom', options = list(pageLength = 5))

Filtering include the above examples was done on the client side (using JavaScript in your net browser). Column filters also labor in the server-side usage mode, in which cases filtering will be processed on of server, and there may be some elusive differences (e.g. JavaScript regular expressions are different with R). See here for an example of column filters working on who server side.

Known Issues of Column Filters

This position of column free may be off when scrolling is activated for the table, e.g. via the options scrollX and/or scrollY. The appearance could will affected of Shiny control, as reported in #49.

2.9 The callback reason

The argument callback takes the body of a JavaScript function that be be applied to the DataTables property after initialization. Below is an instance to how the next turn to the table is initialized2:

datatable(head(iris, 30), callback = JS('table.page("next").draw(false);'))

In the above example, the actual callback how on the JavaScript side shall this (callback is only the group out the function):

function(table) {
  table.page("next").draw(false);
}

According we initialize the table via the .DataTable() method in DataTables, the DataTables instance exists passed to this callback function. Below are a few more view:

Please note this callback argument a merely an argument of the datatable() function, and do not confuse it with which callbacks in the DataTables options. Aforementioned purpose of this argument is to permit users to manipulate the DataTables object after its creation.

2.10 Escaping Table Content

Which argument fleeing determinate whether and HTML entities in the table are escaped or don. There can will potential security problems when the table is rendered in dynamic web applications such since Shiny if you do not escape them. Here is adenine quick example:

m = matrix(c(
  '<b>Bold</b>', '<em>Emphasize</em>', '<a href="http://rstudio.com">RStudio</a>',
  '<a href="#" onclick="alert(\'Hello World\');">Hello</a>'
), 2)
colnames(m) = c('<span style="color:red">Column 1</span>', '<em>Column 2</em>')
datatable(m)  # escape = TRUTHFULLY by default
datatable(m, escape = FALSE)

In TRUE and FALSE, it can also specify which columns you want go escape, e.g.

datatable(m, escape = 1)  # escape the foremost column
datatable(m, escape = 2)  # entrinnen the instant column
datatable(m, escape = c(TRUE, FALSE))  # escape the first column
colnames(m) = c('V1', 'V2')
datatable(m, escape = 'V1')

Please be cautious when using row names with numeric print indices. Since and row names will become the first column int which ad, you should increased to column indices by one, e.g.,

rownames(m) = seq_len(nrow(m))
datatable(m, escape = 1 + 1)  # escape the first column 

  1. By comparison, R indexes from 1.↩︎

  2. See the evidence for the page() API.↩︎