Scramblings

Dev scratchpad. Digital garden

Hugo - Integrating Datatables

May 27, 2024 | Reading Time: 5 min

In this guide, we will walk through the steps to integrate Datatables into a Hugo site. We will cover both node-based and CDN-based installations, and discuss the necessary page layout, table layout, and Datatable initialization functions.

What Datatables Provide

Datatables offer numerous features to enhance the user experience when working with tabular data:

  • Sorting: Allows users to sort data by clicking on column headers.
  • Searching: Provides a search box to filter table data.
  • Pagination: Splits the table into pages for easier navigation.
  • Responsive Design: Ensures tables look good on different screen sizes.
  • Customization: Extensive options to customize the appearance and behavior of tables.

Step 1: Installation

Datatables provides various styling and js options that supports jQuery, bootstrap and others. Below we talk about Bootstrap5 packages, but this can be adopted to any other styling system too.

Node-Based Installation

  • For a node-based Hugo setup, you can install Datatables and its dependencies using npm:

    1npm install jquery datatables.net datatables.net-bs5
    
  • After installation, ensure that the required JS and CSS files are included in your Hugo site’s assets.

  • First, you would need to mount the node_modules to the assets folder. This can be done in config.toml:

    1[module]
    2[[module.mounts]]
    3source = "node_modules"
    4target = "assets/vendor"
    
  • Note that if you do this, you have to explicitly mount other folders too. Defaults are shown in the Hugo documentation here .

  • Now you have to refer to the mount path (i.e., assets/vendor above) when using Hugo pipes to process this file. For example:

    1{{ $datatablesBS5CSS := resources.Get "vendor/datatables.net-bs5/css/dataTables.bootstrap5.min.css" }}
    2<link rel="stylesheet" href="{{ $datatablesBS5CSS.RelPermalink }}">
    

CDN-Based Installation

  • For a simpler approach, you can use the CDN links to include Datatables and its dependencies:

    1<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css">
    2
    3<!-- These can be included in the specific page directly so that other pages are not impacted-->
    4<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    5<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
    6<script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js"></script>
    

Step 2: Content Page

  • The content page defines the table structure to use with Datatables.

  • First, you can create the content with a specialized layout. For example at: content/movies/_index.md.

  • If your actual data comes from a csv file, you can load that file and populate the table using a shortcode. Else, your data can directly go as content in the page.

  • Below is a sample content page and the associated csv read and table populate shortcode.

  • Sample content file:

     1---
     2title: "Movie ratings"
     3layout: "movie"
     4type: "movie"
     5toc: false
     6summary: "A table of my watched movies over the years and associated metadata along with my ratings."
     7---
     8
     9<!-- Uncomment this invocation of shortcode  -->
    10{{/* < csvtable src="movies/imdbratings_26052024.csv" > */}} -->
    
  • The csvtable shortcode defined at layouts/shortcodes/csvtable.html:

     1{{ $path := .Get "src" }}
     2<!-- Read the csv -->
     3{{ $csv := readFile $path }}
     4{{ if $csv }}
     5<!-- Unmarshal it as a data object -->
     6{{ $data := $csv | transform.Unmarshal }}
     7<!-- Populate the table -->
     8<table id="movieRatingsDataTable" class="display">
     9  <thead>
    10    <!-- Declare the columns for your table -->
    11    <tr>
    12      <th>No</th>
    13      <th>Title</th>
    14      <th>My Rating</th>
    15      <th>IMDb Rating</th>
    16      <th>Date Rated</th>
    17      <th>Release Year</th>
    18      <th>Directors</th>
    19      <th>Genres</th>
    20    </tr>
    21  </thead>
    22  <!-- Populate rows -->
    23  <tbody>
    24    {{ range $index, $row := $data }}
    25    {{ if ne $index 0 }}
    26    <tr>
    27      <!-- Note that the row object is dependent on your csv structure. Map proper column names. -->
    28      <td>{{ $index }}</td>
    29      <td>
    30        <a href="{{ index $row 5 }}" target="_blank">{{ index $row 3 }}</a>
    31      </td>
    32      <td>{{ index $row 1 }}</td>
    33      <td>{{ index $row 7 }}</td>
    34      <td>{{ index $row 2 }}</td>
    35      <td>{{ index $row 9 }}</td>
    36      <td>{{ index $row 13 }}</td>
    37      <td>{{ index $row 10 }}</td>
    38    </tr>
    39    {{ end }}
    40    {{ end }}
    41  </tbody>
    42</table>
    43{{ else }}
    44<p>Error: CSV file not found.</p>
    45{{ end }}
    

Step 3: Page Layout

  • The above page content now needs to be served using a specialized layout.

  • This layout includes the Datatables setup as well.

  • The name of the file and the layout name used in the content page should match.

  • Add the javascript dependencies here.

  • For example, layouts/_default/movie.html:

     1{{ define "main" }}
     2<div class="container" style="max-width: 1080px; margin: auto; overflow-x: auto">
     3  <h1 style="text-align: center; margin-bottom: 3rem">{{ .Title }}</h1>
     4  <!-- The .Content will be the page content loaded by Hugo -->
     5  <section>{{ .Content }}</section>
     6</div>
     7
     8<!-- Ensure scripts are deferred to improve page render performance -->
     9<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
    10<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js" defer></script>
    11<script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js" defer></script>
    12<script src="/js/movietables.js" defer></script>
    13{{ end }}
    

Step 4: Datatable Initialization Function

  • The Datatable initialization is a javascript function.

  • You can write that as a separate script in static/js and use it, or add it in assets/js and load it via resource.Get as shown before or even embed it directly into the page layout file.

  • All your options related to page render can be added here.

  • Below is a simple example. This can be enhanced further as per your styling needs.

     1jQuery(function () {
     2  $("#movieRatingsDataTable").DataTable({
     3    ordering: true,
     4    order: [[4, "desc"]], // Sort by the "Date Rated" column, assumed to be the fifth column (index 4)
     5    pageLength: 10, // Set the default number of rows per page
     6    columnDefs: [
     7      { orderable: false, targets: [6, 7] }, // Make the Directors and Genres columns non-orderable
     8      { className: "dt-head-center", targets: "_all" }, // Center align all header cells
     9      { className: "dt-body-center", targets: "_all" }, // Center align all body cells
    10    ],
    11    pagingType: "full_numbers", // Enhance pagination controls
    12    responsive: true, // Enable responsiveness
    13    scrollX: true, // Enable horizontal scrolling
    14    language: {
    15      search: "Filter records:", // Customizing the search box text
    16      lengthMenu: "Display _MENU_ records per page", // Customize the length menu text
    17      info: "Showing page _PAGE_ of _PAGES_", // Customize the page information text
    18    },
    19  });
    20});
    

Conclusion

  • With these steps, you can effectively integrate Datatables into your Hugo site, providing a robust and user-friendly way to display tabular data.
  • Example integration is present in this sites Movie ratings page here