Translating DataTables.net Config to R

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  message = FALSE,
  warning = FALSE
)
library(DT2)

The 1:1 Mapping Principle

DT2's options argument maps directly to the DataTables JavaScript configuration object. An R named list becomes a JS object; R vectors become JS arrays. This means you can translate any example from datatables.net directly to R.

Translation Rules

| JavaScript | R | |---|---| | { key: value } | list(key = value) | | [1, 2, 3] | c(1, 2, 3) or list(1, 2, 3) | | true / false | TRUE / FALSE | | null | NULL | | "string" | "string" | | function(d) { ... } | htmlwidgets::JS("function(d) { ... }") |

Example: JS to R

JavaScript (from datatables.net):

$('#myTable').DataTable({
  pageLength: 25,
  ordering: true,
  language: {
    search: "Filter:",
    lengthMenu: "Show _MENU_ entries"
  },
  columnDefs: [
    { targets: 0, visible: false },
    { targets: [1, 2], className: "text-center" }
  ]
});

R (with DT2):

dt2(iris, options = list(
  pageLength = 25,
  ordering   = TRUE,
  language   = list(
    search     = "Filter:",
    lengthMenu = "Show _MENU_ entries"
  ),
  columnDefs = list(
    list(targets = 0, visible = FALSE),
    list(targets = c(1, 2), className = "text-center")
  )
))

Layout — The Complete Guide

DataTables 2 replaced the old dom string with layout, a structured way to position elements around the table. This is the most important change from DataTables 1.x.

Position grid

+------------------+------------------+
| topStart         | topEnd           |
+------------------+------------------+
| top (full width)                    |
+------------------+------------------+
| top2Start        | top2End          |
+------------------+------------------+
|               TABLE                 |
+------------------+------------------+
| bottomStart      | bottomEnd        |
+------------------+------------------+
| bottom (full width)                 |
+------------------+------------------+
| bottom2Start     | bottom2End       |
+------------------+------------------+

Available elements

| Element | Description | |---|---| | "search" | Search/filter input | | "paging" | Page navigation | | "info" | "Showing X to Y of Z entries" | | "pageLength" | Entries per page selector | | "buttons" | Buttons toolbar (requires Buttons extension) | | "searchBuilder" | SearchBuilder (requires extension) | | "searchPanes" | SearchPanes (requires extension) | | NULL | Remove whatever would normally be in that position |

Default layout

When you don't specify layout, DataTables uses:

layout = list(
  topStart    = "pageLength",
  topEnd      = "search",
  bottomStart = "info",
  bottomEnd   = "paging"
)

Rearranging

Move search to the left, page length to the right:

dt2(iris, options = list(
  pageLength = 5,
  layout = list(
    topStart = list(search = list(placeholder = "Filter...")),
    topEnd   = "pageLength"
  )
))

Removing elements

Set any position to NULL:

dt2(iris, options = list(
  pageLength = 10,
  searching = FALSE,
  layout = list(
    topStart  = NULL,      # no page length selector
    topEnd    = NULL,      # no search box
    bottomStart = NULL,    # no info
    bottomEnd = "paging"   # only pagination
  )
))

Multiple elements in one position

Wrap them in a list:

dt2(iris, options = list(
  pageLength = 5,
  layout = list(
    topStart  = list("pageLength", "info"),
    topEnd    = "search",
    bottomEnd = "paging"
  )
))

Full-width rows

Use top, top2, bottom, bottom2 for full-width rows:

dt2(iris, options = list(
  layout = list(
    top       = "search",       # full-width search bar
    topStart  = "pageLength",
    topEnd    = "buttons",
    bottomEnd = "paging"
  )
))

Buttons in layout

Place the Buttons toolbar in any position:

# Buttons on the left
dt2(iris[1:15, ], options = list(
  buttons = list("copy", "csv", "excel"),
  layout = list(
    topStart  = "buttons",
    topEnd    = "search",
    bottomEnd = "paging"
  )
))
# Buttons on the bottom
dt2(iris[1:15, ], options = list(
  buttons = list("copy", "csv"),
  layout = list(
    topEnd      = "search",
    bottomStart = "buttons",
    bottomEnd   = "paging"
  )
))

Customized search box

dt2(iris, options = list(
  pageLength = 5,
  layout = list(
    topEnd = list(search = list(
      placeholder = "Type to filter...",
      text = "Search:"
    ))
  )
))

Complete custom layout

dt2(mtcars[1:20, ], options = list(
  pageLength = 10,
  buttons = list(
    list(extend = "collection", text = "Export \u25BC",
         buttons = list("copyHtml5", "csvHtml5", "excelHtml5")),
    list(extend = "colvis", text = "Columns")
  ),
  layout = list(
    topStart    = "buttons",
    topEnd      = list(search = list(placeholder = "Filter...")),
    bottomStart = "info",
    bottomEnd   = "paging"
  )
))

Migrating from dom

If you're coming from DataTables 1.x or the DT package:

| Old dom | New layout | |---|---| | "frtip" | (default — no need to specify) | | "tp" | list(topStart = NULL, topEnd = NULL, bottomStart = NULL, bottomEnd = "paging") | | "Bfrtip" | list(topStart = "buttons") | | "lfBrtip" | list(topStart = list("pageLength", "buttons")) |

DT2 will automatically convert dom strings containing "B" to the layout equivalent, but using layout directly is recommended.

Using htmlwidgets::JS() for Callbacks

Whenever DataTables expects a JavaScript function, wrap it in htmlwidgets::JS():

dt2(iris, options = list(
  pageLength = 5,
  createdRow = htmlwidgets::JS("
    function(row, data, dataIndex) {
      if (data['Sepal.Length'] > 5) {
        row.style.backgroundColor = '#fff3cd';
      }
    }
  ")
))

Common Callbacks

| DataTables Option | Purpose | |---|---| | createdRow | Modify each row after creation | | initComplete | Run code after table initializes | | drawCallback | Run code after each draw | | headerCallback | Modify the header after draw | | footerCallback | Modify the footer after draw | | columns.render | Custom cell rendering |

Column Renderers

Built-in DataTables Renderers

DataTables v2 provides built-in renderers accessible via DataTable.render.*:

dt2(mtcars[1:10, c("mpg", "hp", "wt")], options = list(
  columnDefs = list(
    list(
      targets = 0,
      render = htmlwidgets::JS("DataTable.render.number('.', ',', 1, '', ' mpg')")
    ),
    list(
      targets = 1,
      render = htmlwidgets::JS("DataTable.render.number(',', '.', 0, '', ' hp')")
    )
  )
))

Custom Render Function

progress_render <- htmlwidgets::JS("
  function(data, type, row, meta) {
    if (type !== 'display') return data;
    var pct = Math.min(100, Math.max(0, parseFloat(data)));
    var color = pct > 70 ? '#198754' : (pct > 40 ? '#ffc107' : '#dc3545');
    return '<div style=\"background:#eee;border-radius:4px;overflow:hidden\">' +
           '<div style=\"width:' + pct + '%;background:' + color +
           ';height:14px;border-radius:4px\"></div></div>';
  }
")

df <- data.frame(
  task     = c("Design", "Backend", "Testing", "Deploy"),
  progress = c(85, 60, 30, 95)
)

dt2(df, options = list(
  pageLength = 10,
  columnDefs = list(
    list(targets = 1, render = progress_render)
  )
))

Internationalization (i18n)

Inline language object

dt2(iris[1:10, ], options = list(
  pageLength = 5,
  language = list(
    search       = "Buscar:",
    lengthMenu   = "Mostrar _MENU_ registros",
    info         = "Mostrando _START_ a _END_ de _TOTAL_",
    paginate     = list(
      first    = "<<",
      previous = "<",
      `next`   = ">",
      last     = ">>"
    ),
    zeroRecords  = "Nenhum registro encontrado",
    emptyTable   = "Tabela vazia"
  )
))

CDN language URL

DataTables provides ready-made translation files for 70+ languages:

dt2(iris, options = list(
  language = list(
    url = "https://cdn.datatables.net/plug-ins/2.3.4/i18n/pt-BR.json"
  )
))

Debugging

Open the browser console and look for [DT2] log messages. Access the DataTables API object directly via JavaScript:

// In browser console:
var el = document.getElementById('my_table');
var api = el._dt2;
api.page.info();      // pagination state
api.order();          // current ordering
api.search();         // current search term
api.rows().data();    // all row data


Try the DT2 package in your browser

Any scripts or data that you put into this service are public.

DT2 documentation built on June 14, 2026, 9:06 a.m.