:github_url: https://github.com/kivymd/KivyMD/blob/master/kivymd/uix/datatables/datatables.py

DataTables
==========

.. py:module:: kivymd.uix.datatables.datatables

.. autoapi-nested-parse::

   Components/DataTables
   =====================

   .. rubric:: Data tables display sets of data across rows and columns.

   .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-m3-previous.png
       :align: center

   .. note:: `MDDataTable` allows developers to sort the data provided by column.
       This happens thanks to the use of an external function that you can bind
       while you're defining the table columns. Be aware that the sorting function
       must return a 2 value list in the format of: `[Index, Sorted_Row_Data]`

       This is because the index list is needed to allow MDDataTable to keep track
       of the selected rows. and, after the data is sorted, update the row
       checkboxes.


API - :mod:`kivymd.uix.datatables.datatables`
---------------------------------------------

.. py:class:: MDDataTable(**kwargs)




   Datatable class.

   For more information, see in the
   :class:`~kivymd.theming.ThemableBehavior` and
   :class:`~kivy.uix.anchorlayout.AnchorLayout` classes documentation.

   :Events:
       :attr:`on_row_press`
           Called when a table row is clicked.
       :attr:`on_check_press`
           Called when the check box in the table row is checked.

   .. rubric:: Use events as follows

   .. code-block:: python

       from kivy.metrics import dp

       from kivymd.app import MDApp
       from kivymd.uix.datatables import MDDataTable
       from kivymd.uix.screen import MDScreen


       class Example(MDApp):
           def build(self):
               self.data_tables = MDDataTable(
                   use_pagination=True,
                   check=True,
                   column_data=[
                       ("No.", dp(30)),
                       ("Status", dp(30)),
                       ("Signal Name", dp(60), self.sort_on_signal),
                       ("Severity", dp(30)),
                       ("Stage", dp(30)),
                       ("Schedule", dp(30), self.sort_on_schedule),
                       ("Team Lead", dp(30), self.sort_on_team),
                   ],
                   row_data=[
                       (
                           "1",
                           ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"),
                           "Astrid: NE shared managed",
                           "Medium",
                           "Triaged",
                           "0:33",
                           "Chase Nguyen",
                       ),
                       (
                           "2",
                           ("alert-circle", [1, 0, 0, 1], "Offline"),
                           "Cosmo: prod shared ares",
                           "Huge",
                           "Triaged",
                           "0:39",
                           "Brie Furman",
                       ),
                       (
                           "3",
                           (
                               "checkbox-marked-circle",
                               [39 / 256, 174 / 256, 96 / 256, 1],
                               "Online",
                           ),
                           "Phoenix: prod shared lyra-lists",
                           "Minor",
                           "Not Triaged",
                           "3:12",
                           "Jeremy lake",
                       ),
                       (
                           "4",
                           (
                               "checkbox-marked-circle",
                               [39 / 256, 174 / 256, 96 / 256, 1],
                               "Online",
                           ),
                           "Sirius: NW prod shared locations",
                           "Negligible",
                           "Triaged",
                           "13:18",
                           "Angelica Howards",
                       ),
                       (
                           "5",
                           (
                               "checkbox-marked-circle",
                               [39 / 256, 174 / 256, 96 / 256, 1],
                               "Online",
                           ),
                           "Sirius: prod independent account",
                           "Negligible",
                           "Triaged",
                           "22:06",
                           "Diane Okuma",
                       ),
                   ],
                   sorted_on="Schedule",
                   sorted_order="ASC",
                   elevation=2,
               )
               self.data_tables.bind(on_row_press=self.on_row_press)
               self.data_tables.bind(on_check_press=self.on_check_press)
               screen = MDScreen()
               screen.add_widget(self.data_tables)
               return screen

           def on_row_press(self, instance_table, instance_row):
               '''Called when a table row is clicked.'''

               print(instance_table, instance_row)

           def on_check_press(self, instance_table, current_row):
               '''Called when the check box in the table row is checked.'''

               print(instance_table, current_row)

           # Sorting Methods:
           # since the https://github.com/kivymd/KivyMD/pull/914 request, the
           # sorting method requires you to sort out the indexes of each data value
           # for the support of selections.
           #
           # The most common method to do this is with the use of the builtin function
           # zip and enumerate, see the example below for more info.
           #
           # The result given by these funcitons must be a list in the format of
           # [Indexes, Sorted_Row_Data]

           def sort_on_signal(self, data):
               return zip(*sorted(enumerate(data), key=lambda l: l[1][2]))

           def sort_on_schedule(self, data):
               return zip(
                   *sorted(
                       enumerate(data),
                       key=lambda l: sum(
                           [
                               int(l[1][-2].split(":")[0]) * 60,
                               int(l[1][-2].split(":")[1]),
                           ]
                       ),
                   )
               )

           def sort_on_team(self, data):
               return zip(*sorted(enumerate(data), key=lambda l: l[1][-1]))


       Example().run()

   .. py:attribute:: column_data

      Data for header columns.

      .. tabs::

          .. tab:: Imperative python style

              .. code-block:: python

                  from kivy.metrics import dp

                  from kivymd.app import MDApp
                  from kivymd.uix.datatables import MDDataTable
                  from kivy.uix.anchorlayout import AnchorLayout


                  class Example(MDApp):
                      def build(self):
                          self.theme_cls.theme_style = "Dark"
                          self.theme_cls.primary_palette = "Orange"

                          layout = AnchorLayout()
                          self.data_tables = MDDataTable(
                              size_hint=(0.7, 0.6),
                              use_pagination=True,
                              check=True,
                              # name column, width column, sorting function column(optional), custom tooltip
                              column_data=[
                                  ("No.", dp(30), None, "Custom tooltip"),
                                  ("Status", dp(30)),
                                  ("Signal Name", dp(60)),
                                  ("Severity", dp(30)),
                                  ("Stage", dp(30)),
                                  ("Schedule", dp(30), lambda *args: print("Sorted using Schedule")),
                                  ("Team Lead", dp(30)),
                              ],
                          )
                          layout.add_widget(self.data_tables)
                          return layout


                  Example().run()

          .. tab:: Declarative python style

              .. code-block:: python

                  from kivy.metrics import dp

                  from kivymd.app import MDApp
                  from kivymd.uix.anchorlayout import MDAnchorLayout
                  from kivymd.uix.datatables import MDDataTable


                  class Example(MDApp):
                      def build(self):
                          self.theme_cls.theme_style = "Dark"
                          self.theme_cls.primary_palette = "Orange"
                          return MDAnchorLayout(
                              MDDataTable(
                                  size_hint=(0.7, 0.6),
                                  use_pagination=True,
                                  check=True,
                                  # name column, width column, sorting function column(optional)
                                  column_data=[
                                      ("No.", dp(30)),
                                      ("Status", dp(30)),
                                      ("Signal Name", dp(60)),
                                      ("Severity", dp(30)),
                                      ("Stage", dp(30)),
                                      ("Schedule", dp(30),
                                       lambda *args: print("Sorted using Schedule")),
                                      ("Team Lead", dp(30)),
                                  ],
                              )
                          )


                  Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-column-data.png
          :align: center

      :attr:`column_data` is an :class:`~kivy.properties.ListProperty`
      and defaults to `[]`.

      .. note:: The functions which will be called for sorting must accept a data
          argument and return the sorted data. Incoming data format will be
          similar to the provided row_data except that it'll be all list instead
          of tuple like below. Any icon provided initially will also be there in
          this data so handle accordingly.

          .. code-block:: python

              [
                  [
                      "1",
                      ["icon", "No Signal"],
                      "Astrid: NE shared managed",
                      "Medium",
                      "Triaged",
                      "0:33",
                      "Chase Nguyen",
                  ],
                  [
                      "2",
                      "Offline",
                      "Cosmo: prod shared ares",
                      "Huge",
                      "Triaged",
                      "0:39",
                      "Brie Furman",
                  ],
                  [
                      "3",
                      "Online",
                      "Phoenix: prod shared lyra-lists",
                      "Minor",
                      "Not Triaged",
                      "3:12",
                      "Jeremy lake",
                  ],
                  [
                      "4",
                      "Online",
                      "Sirius: NW prod shared locations",
                      "Negligible",
                      "Triaged",
                      "13:18",
                      "Angelica Howards",
                  ],
                  [
                      "5",
                      "Online",
                      "Sirius: prod independent account",
                      "Negligible",
                      "Triaged",
                      "22:06",
                      "Diane Okuma",
                  ],
              ]

          You must sort inner lists in ascending order and return the sorted data
          in the same format.


   .. py:attribute:: row_data

      Data for rows. To add icon in addition to a row data, include a tuple with
      This property stores the row data used to display each row in the DataTable
      To show an icon inside a column in a row, use the folowing format in the
      row's columns.

      Format:

      `("MDicon-name", [icon color in rgba], "Column Value")`

      Example:

      .. code-block:: python

          [...]
          row_data = [

              # row 1
              [
                  "value 1",
                  "value 2",
                  # the third value will have an icon inside the box
                  ["home", [128/255, 48/255, 76/255, 1], "Offie" ]
              ],

              # row 2
              [
                  "value 1",
                  "value 2",
                  # the third value will have an icon inside the box
                  ["git", [1, 0.1, 0.1, 1], "Git Repo" ]
              ]
          ]

      For a more complex example see below.

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.uix.anchorlayout import AnchorLayout

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable


          class Example(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = AnchorLayout()
                  data_tables = MDDataTable(
                      size_hint=(0.9, 0.6),
                      column_data=[
                          ("Column 1", dp(30)),
                          ("Column 2", dp(30)),
                          ("Column 3", dp(50), self.sort_on_col_3),
                          ("Column 4", dp(30)),
                          ("Column 5", dp(30)),
                          ("Column 6", dp(30)),
                          ("Column 7", dp(30), self.sort_on_col_2),
                      ],
                      row_data=[
                          # The number of elements must match the length
                          # of the `column_data` list.
                          (
                              "1",
                              ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"),
                              "Astrid: NE shared managed",
                              "Medium",
                              "Triaged",
                              "0:33",
                              "Chase Nguyen",
                          ),
                          (
                              "2",
                              ("alert-circle", [1, 0, 0, 1], "Offline"),
                              "Cosmo: prod shared ares",
                              "Huge",
                              "Triaged",
                              "0:39",
                              "Brie Furman",
                          ),
                          (
                              "3",
                              (
                                  "checkbox-marked-circle",
                                  [39 / 256, 174 / 256, 96 / 256, 1],
                                  "Online",
                              ),
                              "Phoenix: prod shared lyra-lists",
                              "Minor",
                              "Not Triaged",
                              "3:12",
                              "Jeremy lake",
                          ),
                          (
                              "4",
                              (
                                  "checkbox-marked-circle",
                                  [39 / 256, 174 / 256, 96 / 256, 1],
                                  "Online",
                              ),
                              "Sirius: NW prod shared locations",
                              "Negligible",
                              "Triaged",
                              "13:18",
                              "Angelica Howards",
                          ),
                          (
                              "5",
                              (
                                  "checkbox-marked-circle",
                                  [39 / 256, 174 / 256, 96 / 256, 1],
                                  "Online",
                              ),
                              "Sirius: prod independent account",
                              "Negligible",
                              "Triaged",
                              "22:06",
                              "Diane Okuma",
                          ),
                      ],
                  )
                  layout.add_widget(data_tables)
                  return layout

              def sort_on_col_3(self, data):
                  return zip(
                      *sorted(
                          enumerate(data),
                          key=lambda l: l[1][3]
                      )
                  )

              def sort_on_col_2(self, data):
                  return zip(
                      *sorted(
                          enumerate(data),
                          key=lambda l: l[1][-1]
                      )
                  )

          Example().run()


      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-row-data.png
          :align: center

      Custom widgets in cells.

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.uix.anchorlayout import AnchorLayout

          from kivymd.app import MDApp
          from kivymd.uix.button import MDButton, MDButtonText
          from kivymd.uix.chip import MDChip, MDChipText
          from kivymd.uix.datatables import MDDataTable


          class MyMDChip(MDChip):
              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)
                  self.widgets = [
                      MDChipText(
                          text="Chip"
                      ),
                  ]


          class MyMDButton(MDButton):
              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)
                  self.widgets = [
                      MDButtonText(
                          text="Button"
                      )
                  ]


          class Example(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = AnchorLayout()

                  def on_activate(row_index: int, row_data: list) -> None:
                      '''
                      Callback function for the switch widget in the table row.

                      Called when the MDSwitch in a table row is toggled.

                      :param row_index: Index of the row in the table (0-based)
                      :param row_data: List of data values for the row (all columns)

                      Example:
                          When a switch is toggled in the "Status" column:
                          >>> on_activate(0, ['1', 'John Doe', {'viewclass': 'MDSwitch', ...}])
                          Activate row 0: ['1', 'John Doe', {'viewclass': 'MDSwitch', ...}]
                      '''

                      print(f"Activate row {row_index}: {row_data}")

                  def on_press(row_index: int, row_data: list) -> None:
                      '''
                      Callback function for button widgets in the table row.
                      Called when a button (e.g., MyMDButton) in a table row is pressed/released.
                      '''

                      print(f"Press button {row_index}: {row_data}")

                  def on_release(row_index: int, row_data: list) -> None:
                      '''
                      Callback function for check widgets in the table row.
                      Called when a button (e.g., MyMDChip) in a table row is pressed/released.
                      '''

                      print(f"Press check {row_index}: {row_data}")

                  data_tables = MDDataTable(
                      size_hint=(0.95, 0.8),
                      use_pagination=True,
                      rows_num=5,
                      check=True,
                      column_data=[
                          ("ID", dp(40)),
                          ("Name", dp(40)),
                          ("Status", dp(40)),
                      ],
                      row_data=[
                          (
                              "1",
                              "John Doe",
                              {"viewclass": "MyMDButton", "on_press": on_press},
                          ),
                          (
                              "2",
                              "Jane Smith",
                              {"viewclass": "MDSwitch", "on_active": on_activate},
                          ),
                          (
                              "3",
                              "Nicol Andersson",
                              {"viewclass": "MyMDChip", "on_release": on_release},
                          ),
                      ]
                  )

                  layout.add_widget(data_tables)
                  return layout


          if __name__ == "__main__":
              Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-custom-widgets.png
          :align: center

      Custom widgets with children in cells.

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.properties import StringProperty
          from kivy.uix.anchorlayout import AnchorLayout

          from kivymd.app import MDApp
          from kivymd.uix.button import MDButton, MDButtonText
          from kivymd.uix.chip import MDChip, MDChipText
          from kivymd.uix.datatables import MDDataTable
          from kivymd.uix.boxlayout import MDBoxLayout  # NOQA
          from kivymd.uix.button import MDIconButton  # NOQA


          class MyMDChip(MDChip):
              text = StringProperty()

              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)

              def on_text(self, instance, value):
                  self.widgets = [
                      MDChipText(
                          text=value
                      ),
                  ]


          class MyMDButton(MDButton):
              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)
                  self.widgets = [
                      MDButtonText(
                          text="Button"
                      )
                  ]


          class Example(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = AnchorLayout()

                  def on_activate(row_index: int, row_data: list) -> None:
                      print(f"Activate row {row_index}: {row_data}")

                  def on_press(row_index: int, row_data: list) -> None:
                      print(f"Press button {row_index}: {row_data}")

                  def on_release(row_index: int, row_data: list) -> None:
                      print(f"Release chip {row_index}: {row_data}")

                  def on_edit(row_index: int, row_data: list) -> None:
                      print(f"Edit row {row_index}: {row_data}")

                  def on_delete(row_index: int, row_data: list) -> None:
                      print(f"Delete row {row_index}: {row_data}")

                  def on_view(row_index: int, row_data: list) -> None:
                      print(f"View row {row_index}: {row_data}")

                  data_tables = MDDataTable(
                      size_hint=(0.95, 0.8),
                      use_pagination=True,
                      rows_num=5,
                      check=True,
                      column_data=[
                          ("ID", dp(30)),
                          ("Name", dp(40)),
                          ("Status", dp(40)),
                          ("Actions", dp(40)),
                      ],
                      row_data=[
                          (
                              "1",
                              "John Doe",
                              {"viewclass": "MyMDButton", "on_press": on_press},
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "eye",
                                          "on_release": on_view,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "pencil",
                                          "on_release": on_edit,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "delete",
                                          "on_release": on_delete,
                                      },
                                  ]
                              },
                          ),
                          (
                              "2",
                              "Jane Smith",
                              {"viewclass": "MDSwitch", "on_active": on_activate},
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "eye",
                                          "on_release": on_view,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "pencil",
                                          "on_release": on_edit,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "delete",
                                          "on_release": on_delete,
                                      },
                                  ]
                              },
                          ),
                          (
                              "3",
                              "Nicol Andersson",
                              {"viewclass": "MyMDChip", "text": "Delete", "on_release": on_release},
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "eye",
                                          "on_release": on_view,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "pencil",
                                          "on_release": on_edit,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "delete",
                                          "on_release": on_delete,
                                      },
                                  ]
                              },
                          ),
                          (
                              "4",
                              "Alice Brown",
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MyMDChip",
                                          "text": "Active",
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "information",
                                          "on_release": on_view,
                                      },
                                  ]
                              },
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "pencil",
                                          "on_release": on_edit,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "delete",
                                          "on_release": on_delete,
                                      },
                                  ]
                              },
                          ),
                          (
                              "5",
                              "Bob Johnson",
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MyMDChip",
                                          "text": "Pending",
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "information",
                                          "on_release": on_view,
                                      },
                                  ]
                              },
                              {
                                  "viewclass": "MDBoxLayout",
                                  "spacing": dp(4),
                                  "children": [
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "pencil",
                                          "on_release": on_edit,
                                      },
                                      {
                                          "viewclass": "MDIconButton",
                                          "icon": "delete",
                                          "on_release": on_delete,
                                      },
                                  ]
                              },
                          ),
                      ]
                  )

                  layout.add_widget(data_tables)
                  return layout


          if __name__ == "__main__":
              Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-custom-widgets-children.png
          :align: center

      :attr:`row_data` is an :class:`~kivy.properties.ListProperty`
      and defaults to `[]`.


   .. py:attribute:: sorted_on

      Column name upon which the data is already sorted.

      If the table data is showing an already sorted data then this can be used
      to indicate upon which column the data is sorted.

      :attr:`sorted_on` is an :class:`~kivy.properties.StringProperty`
      and defaults to `''`.


   .. py:attribute:: sorted_order

      Order of already sorted data. Must be one of `'ASC'` for ascending or
      `'DSC'` for descending order.

      :attr:`sorted_order` is an :class:`~kivy.properties.OptionProperty`
      and defaults to `'ASC'`.


   .. py:attribute:: check

      Use or not use checkboxes for rows.

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-check.png
          :align: center

      :attr:`check` is an :class:`~kivy.properties.BooleanProperty`
      and defaults to `False`.


   .. py:attribute:: use_pagination

      Use page pagination for table or not.

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.uix.anchorlayout import AnchorLayout

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable


          class Example(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = AnchorLayout()
                  data_tables = MDDataTable(
                      size_hint=(0.9, 0.6),
                      use_pagination=True,
                      column_data=[
                          ("No.", dp(30)),
                          ("Column 1", dp(30)),
                          ("Column 2", dp(30)),
                          ("Column 3", dp(30)),
                          ("Column 4", dp(30)),
                          ("Column 5", dp(30)),
                      ],
                      row_data=[
                          (f"{i + 1}", "1", "2", "3", "4", "5") for i in range(50)
                      ],
                  )
                  layout.add_widget(data_tables)
                  return layout


          Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination.png
          :align: center

      :attr:`use_pagination` is an :class:`~kivy.properties.BooleanProperty`
      and defaults to `False`.


   .. py:attribute:: radius

      See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_radius`
      attribute.

      .. versionadded:: 1.2.0

      :attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
      and defaults to `[dp(6), dp(6), dp(6), dp(6)]`.


   .. py:attribute:: rows_num

      The number of rows displayed on one page of the table.

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination-rows-num.png
          :align: center

      :attr:`rows_num` is an :class:`~kivy.properties.NumericProperty`
      and defaults to `10`.


   .. py:attribute:: pagination_menu_pos

      Menu position for selecting the number of displayed rows.
      Available options are `'center'`, `'auto'`.

      .. rubric:: Center

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-top.png
          :align: center

      .. rubric:: Auto

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-auto.png
          :align: center

      :attr:`pagination_menu_pos` is an :class:`~kivy.properties.OptionProperty`
      and defaults to `'center'`.


   .. py:attribute:: pagination_menu_height

      Menu height for selecting the number of displayed rows.

      .. rubric:: 240dp

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-height-240.png
          :align: center

      :attr:`pagination_menu_height` is an :class:`~kivy.properties.NumericProperty`
      and defaults to `'140dp'`.


   .. py:attribute:: background_color

      Background color in the format (r, g, b, a) or string format.
      See :attr:`~kivy.uix.modalview.ModalView.background_color`.

      Use markup strings
      ------------------

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.uix.anchorlayout import AnchorLayout

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable


          class Example(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = AnchorLayout()
                  data_tables = MDDataTable(
                      size_hint=(0.9, 0.6),
                      use_pagination=True,
                      column_data=[
                          ("No.", dp(30)),
                          ("Column 1", dp(30)),
                          ("[color=#52251B]Column 2[/color]", dp(30)),
                          ("Column 3", dp(30)),
                          ("[size=24][color=#C042B8]Column 4[/color][/size]", dp(30)),
                          ("Column 5", dp(30)),
                      ],
                      row_data=[
                          (
                              f"{i + 1}",
                              "[color=#297B50]1[/color]",
                              "[color=#C552A1]2[/color]",
                              "[color=#6C9331]3[/color]",
                              "4",
                              "5",
                          )
                          for i in range(50)
                      ],
                  )
                  layout.add_widget(data_tables)
                  return layout


          Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/datatables-use-markup-strings.png
          :align: center

      :attr:`background_color` is a :class:`~kivy.properties.ColorProperty` and
      defaults to `None`.


   .. py:attribute:: background_color_header

      Background color in the format (r, g, b, a) or string format for
      :class:`~TableHeader` class.

      .. versionadded:: 1.0.0

      .. code-block:: python

          self.data_tables = MDDataTable(
              ...,
              background_color_header="#65275d",
          )

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-header.png
          :align: center

      :attr:`background_color_header` is a :class:`~kivy.properties.ColorProperty` and
      defaults to `None`.


   .. py:attribute:: background_color_cell

      Background color in the format (r, g, b, a) or string format for
      :class:`~CellRow` class.

      .. versionadded:: 1.0.0

      .. code-block:: python

          self.data_tables = MDDataTable(
              ...,
              background_color_header="#65275d",
              background_color_cell="#451938",
          )

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-cell.png
          :align: center

      :attr:`background_color_cell` is a :class:`~kivy.properties.ColorProperty`
      and defaults to `None`.


   .. py:attribute:: background_color_selected_cell

      Background selected color in the format (r, g, b, a) or string format for
      :class:`~CellRow` class.

      .. versionadded:: 1.0.0

      .. code-block:: python

          self.data_tables = MDDataTable(
              ...,
              background_color_header="#65275d",
              background_color_cell="#451938",
              background_color_selected_cell="e4514f",
          )

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-selected-cell.png
          :align: center

      :attr:`background_color_selected_cell` is a :class:`~kivy.properties.ColorProperty` and
      defaults to `None`.


   .. py:attribute:: effect_cls

      Effect class. See ``kivy/effects`` package for more information.

      .. versionadded:: 1.0.0

      :attr:`effect_cls` is an :class:`~kivy.properties.ObjectProperty`
      and defaults to :class:`~kivymd.effects.stiffscroll.StiffScrollEffect`.


   .. py:method:: set_row_checked(row_index: int, checked: bool) -> None

      Sets the checkbox state for a specific row by its index.

      .. versionadded:: 2.0.0

      :param row_index: Row index in `row_data`
      :param checked: True - check the row, False - uncheck the row

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.lang import Builder
          from kivy.properties import ObjectProperty

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable
          from kivymd.uix.screen import MDScreen
          from kivymd.uix.anchorlayout import MDAnchorLayout

          KV = '''
          <TableScreen>
              tablebox: tablebox
              md_bg_color: self.theme_cls.backgroundColor

              MainCard:
                  pos_hint: {"center_x": .5, "center_y": .55}

                  TableBox:
                      id: tablebox

              MDButton:
                  pos_hint: {"center_x": .5, "center_y": .1}
                  on_press: root.check_row_0()

                  MDButtonText:
                      text: "Check row 0"


          <TableBox>


          <MainCard>
              size_hint: None, None
              size: "400dp", "450dp"
              pos_hint: {"center_x": .5, "center_y": .5}
              elevation: 3
              padding: "10dp"
              spacing: "25dp"
          '''

          Builder.load_string(KV)


          class MainCard(MDScreen): ...


          class TableBox(MDAnchorLayout):
              table: MDDataTable

              def add_table(
                  self,
                  column_fields,
                  table_data,
                  refresh=False,
                  use_pagination=True,
                  use_check=True,
                  rows_num=10,
              ):
                  if refresh:
                      self.clear_widgets()

                  data_table = MDDataTable(
                      use_pagination=use_pagination,
                      check=use_check,
                      rows_num=rows_num,
                      column_data=column_fields,
                      row_data=table_data,
                  )

                  self.table = data_table
                  self.add_widget(data_table)


          class TableScreen(MDScreen):
              tablebox = ObjectProperty(None)

              def __init__(self, **kwargs):
                  super().__init__(**kwargs)
                  col_fields = ["field1", "field2"]
                  col_data = [(f, dp(30)) for f in col_fields]
                  table_data = [(f"col1_{i}", f"col2_{i}") for i in range(30)]
                  self.tablebox.add_table(col_data, table_data)

              def check_row_0(self):
                  '''Select the checkbox for row 0.'''

                  self.tablebox.table.set_row_checked(0, True)


          class MainApp(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  return TableScreen()


          if __name__ == "__main__":
              MainApp().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/datatables-use-set_row_checked.gif
          :align: center

      You can select multiple rows at once:

      .. code-block:: python

          def check_row_0_4(self):
              '''Select the checkbox for row 0-4.'''

              self.tablebox.table.set_rows_checked([0, 1, 2, 3, 4], True)

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/datatables-use-set_row_checked-multiple.gif
          :align: center

      Or toggle the selected row:

      .. code-block:: python

          def toggle_row_5(self):
              '''Toggle the checkbox for row 5.'''

              self.tablebox.table.toggle_row_checked(5)

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/datatables-use-set_row_checke_toggle.gif
          :align: center


   .. py:method:: set_rows_checked(row_indices: list, checked: bool) -> None

      Sets the checkbox state for multiple rows.

      .. versionadded:: 2.0.0

      :param row_indices: List of row indices in `row_data`
      :param checked: True - check the rows, False - uncheck the rows


   .. py:method:: set_all_rows_checked(checked: bool) -> None

      Sets the state of all checkboxes in the table.

      :param checked: True - check all rows, False - uncheck all rows


   .. py:method:: toggle_row_checked(row_index: int) -> None

      Toggles the checkbox state for a specific row.

      .. versionadded:: 2.0.0

      :param row_index: Row index in `row_data`


   .. py:method:: is_row_checked(row_index: int) -> bool

      Checks if a specific row is checked.

      .. versionadded:: 2.0.0

      :param row_index: Row index in `row_data`
      :return: True if the row is checked, False otherwise


   .. py:method:: get_checked_row_indices() -> list

      Returns a list of indices of all checked rows.

      :return: List of checked row indices


   .. py:method:: clear_all_checks() -> None

      Unchecks all rows in the table.


   .. py:method:: check_all_rows() -> None

      Checks all rows in the table.


   .. py:method:: update_row_data(instance_data_table, data: list) -> None

      Called when a the widget data must be updated.

      Remember that this is a heavy function. since the whole data set must
      be updated. you can get better results calling this metod with in a
      coroutine.


   .. py:method:: add_row(data: Union[list, tuple]) -> None

      Added new row to common table.
      Argument `data` is the row data from the list :attr:`row_data`.

      .. rubric:: Add/remove row

      .. code-block:: python

          from kivy.metrics import dp

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable
          from kivymd.uix.boxlayout import MDBoxLayout
          from kivymd.uix.floatlayout import MDFloatLayout
          from kivymd.uix.button import MDButton
          from kivymd.uix.button import MDButtonText


          class Example(MDApp):
              data_tables = None

              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = MDFloatLayout()  # root layout
                  # Creating control buttons.
                  button_box = MDBoxLayout(
                      pos_hint={"center_x": 0.5},
                      adaptive_size=True,
                      padding="24dp",
                      spacing="24dp",
                  )

                  for button_text in ["Add row", "Remove row"]:
                      button_box.add_widget(
                          MDButton(
                              MDButtonText(
                                  text=button_text
                              ),
                              on_release=lambda x, y=button_text: self.on_button_press(y)
                          )
                      )

                  # Create a table.
                  self.data_tables = MDDataTable(
                      pos_hint={"center_y": 0.5, "center_x": 0.5},
                      size_hint=(0.9, 0.6),
                      use_pagination=False,
                      column_data=[
                          ("No.", dp(30)),
                          ("Column 1", dp(40)),
                          ("Column 2", dp(40)),
                          ("Column 3", dp(40)),
                      ],
                      row_data=[("1", "1", "2", "3")],
                  )
                  # Adding a table and buttons to the toot layout.
                  layout.add_widget(self.data_tables)
                  layout.add_widget(button_box)

                  return layout

              def on_button_press(self, button_text: str) -> None:
                  '''Called when a control button is clicked.'''

                  try:
                      {
                          "Add row": self.add_row,
                          "Remove row": self.remove_row,
                      }[button_text]()
                  except KeyError:
                      pass

              def add_row(self) -> None:
                  last_num_row = int(self.data_tables.row_data[-1][0])
                  self.data_tables.add_row((str(last_num_row + 1), "1", "2", "3"))

              def remove_row(self) -> None:
                  if len(self.data_tables.row_data) > 1:
                      self.data_tables.remove_row(self.data_tables.row_data[-1])


          Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-add-remove-row.gif
          :align: center

      Deleting checked rows
      ---------------------

      .. code-block:: python

          from kivy.metrics import dp
          from kivy.lang import Builder
          from kivy.clock import Clock

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable
          from kivymd.uix.screen import MDScreen

          KV = '''
          MDBoxLayout:
              orientation: "vertical"
              padding: "56dp"
              spacing: "24dp"

              MDData:
                  id: table_screen

              MDButton:
                  on_release: table_screen.delete_checked_rows()

                  MDButtonText:
                      text: "DELETE CHECKED ROWS"
          '''


          class MDData(MDScreen):
              def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)
                  self.data = [
                      ["1", "Asep Sudrajat", "Male", "Soccer"],
                      ["2", "Egy", "Male", "Soccer"],
                      ["3", "Tanos", "Demon", "Soccer"],
                  ]
                  self.data_tables = MDDataTable(
                      use_pagination=True,
                      check=True,
                      column_data=[
                          ("No", dp(30)),
                          ("No Urut.", dp(30)),
                          ("Alamat Pengirim", dp(30)),
                          ("No Surat", dp(60)),
                      ]
                  )
                  self.data_tables.row_data = self.data
                  self.add_widget(self.data_tables)

              def delete_checked_rows(self):
                  def deselect_rows(*args):
                      self.data_tables.table_data.select_all("normal")

                  for data in self.data_tables.get_row_checks():
                      self.data_tables.remove_row(data)

                  Clock.schedule_once(deselect_rows)


          class MyApp(MDApp):
              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"
                  return Builder.load_string(KV)


          MyApp().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-deleting-checked-rows.gif
          :align: center

      .. versionadded:: 1.0.0


   .. py:method:: remove_row(data: Union[list, tuple]) -> None

      Removed row from common table.
      Argument `data` is the row data from the list :attr:`row_data`.

      See the code in the doc string for the :attr:`add_row` method for more
      information.

      .. versionadded:: 1.0.0


   .. py:method:: update_row(old_data: Union[list, tuple], new_data: Union[list, tuple]) -> None

      Updates a table row.
      Argument `old_data/new_data` is the row data from the list :attr:`row_data`.

      .. rubric:: Update row

      .. code-block:: python

          from kivy.metrics import dp

          from kivymd.app import MDApp
          from kivymd.uix.datatables import MDDataTable
          from kivymd.uix.floatlayout import MDFloatLayout
          from kivymd.uix.button import MDButton, MDButtonText


          class Example(MDApp):
              data_tables = None

              def build(self):
                  self.theme_cls.theme_style = "Dark"
                  self.theme_cls.primary_palette = "Orange"

                  layout = MDFloatLayout()
                  layout.add_widget(
                      MDButton(
                          MDButtonText(
                              text="Change 2 row"
                          ),
                          pos_hint={"center_x": 0.5},
                          on_release=self.update_row,
                          y=24,
                      )
                  )
                  self.data_tables = MDDataTable(
                      pos_hint={"center_y": 0.5, "center_x": 0.5},
                      size_hint=(0.9, 0.6),
                      use_pagination=False,
                      column_data=[
                          ("No.", dp(30)),
                          ("Column 1", dp(40)),
                          ("Column 2", dp(40)),
                          ("Column 3", dp(40)),
                      ],
                      row_data=[(f"{i + 1}", "1", "2", "3") for i in range(3)],
                  )
                  layout.add_widget(self.data_tables)

                  return layout

              def update_row(self, instance_button: MDButton) -> None:
                  self.data_tables.update_row(
                      self.data_tables.row_data[1],  # old row data
                      ["2", "A", "B", "C"],  # new row data
                  )


          Example().run()

      .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-change-row.gif
          :align: center

      .. versionadded:: 1.0.0


   .. py:method:: on_row_press(instance_cell_row) -> None

      Called when a table row is clicked.


   .. py:method:: on_check_press(row_data: list) -> None

      Called when the check box in the table row is checked.

      :param row_data: One of the elements from the :attr:`MDDataTable.row_data` list.


   .. py:method:: get_row_checks() -> list

      Returns all rows that are checked.


   .. py:method:: create_pagination_menu(interval: Union[int, float]) -> None




