Custom columns

As you use tables, you will likely encounter situations that call for a type of column that is not provided by default. While you can easily customize how a column renders, if you find that your application has a repeated pattern that would benefit from a custom column type, you can also define a new type of column.

A common pattern we see is a list of links next to each row for actions such as “edit” or “delete”. For example, consider this output HTML:

<table class="action-table">
  <thead>
    <tr>
      <th>Name</th>
      <th class="actions"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td class="actions">
        <a href="/people/1/edit">Edit</a>
        <a href="/people/1" method="delete">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

You can achieve this by subclassing Katalyst::TableComponent to add the required classes and adding helpers for generating the actions. This allows for a declarative table syntax, something like this:

<%# in your controller: default_table_component ActionTableComponent %>
<%= table_with(collection:) do |row, person| %>
  <% row.text :name %>
  <% row.actions do |cell| %>
    <%= cell.action "Edit", edit_person_path(person) %>
    <%= cell.action "Delete", person_path(person), method: :delete %>
  <% end %>
<% end %>

And the customized component:

class ActionTableComponent < Katalyst::TableComponent
  def actions(column = :_actions, label: "", heading: false, **, &)
    with_cell(ActionsComponent.new(collection:, row:, column:, record:, label:, heading:, **), &)
  end

  def default_html_attributes
    { class: "action-table" }
  end

  class ActionsComponent < Katalyst::Tables::CellComponent
    def action(label, href, **)
      link_to(label, href, **)
    end

    def default_html_attributes
      { class: "actions" }
    end
  end
end

This is a simplistic example – it would be trivial to implement this without the custom component – however, it shows all the requirements for building custom components that are more useful. For example, the action component could generate a context menu instead of simply listing the links inline.