Shared table UI helpers (sorting, paging) for Hiccup-based web UIs.
Shared table UI helpers (sorting, paging) for Hiccup-based web UIs.
(bulk-bar {:keys [form-attrs controls confirm]})The bar that appears once rows are selected: how many, what to do with
them, and how to stop. Inside an Alpine bulk-selection scope (see
alpine/bulk-selection-attrs).
opts:
modal/confirm-modal opts; the form waits for its answerThe bar that appears once rows are selected: how many, what to do with them, and how to stop. Inside an Alpine bulk-selection scope (see `alpine/bulk-selection-attrs`). opts: - :form-attrs the htmx request of #bulk-action-form, e.g. :hx-post - :controls what goes in the form: the action select, the submit button - :confirm `modal/confirm-modal` opts; the form waits for its answer
(column-cells columns cells)cells as the [:td]s under columns, as data-table takes them: each
with its field class and its label, which heads it on a narrow screen.
`cells` as the [:td]s under `columns`, as `data-table` takes them: each with its field class and its label, which heads it on a narrow screen.
(count-badge id total-count)(count-badge id total-count label)A list toolbar's count, "12 records" or in a plural catalogue entry
label of its own. A fragment carries it out of band (htmx/oob) so it
follows the search; put it in an aria-live container.
A list toolbar's count, "12 records" or in a plural catalogue entry `label` of its own. A fragment carries it out of band (`htmx/oob`) so it follows the search; put it in an aria-live container.
(data-table {:keys [url push-url? rows-url hx-target hx-swap columns rows
table-query filters total-count infinite? head-before
head-after colgroup tfoot class]
:or {hx-swap "outerHTML" push-url? true}})A table with sortable headers, an optional row of filter inputs, and
either pagination (placed by the caller, see pagination) or, with
:infinite?, rows that load the next page as the last comes into view.
opts:
A table with sortable headers, an optional row of filter inputs, and
either pagination (placed by the caller, see `pagination`) or, with
:infinite?, rows that load the next page as the last comes into view.
opts:
- :url the list URL the controls request and push
- :push-url? default true; false for a table whose URL is not a page,
so its controls leave the address bar alone
- :rows-url what the last row requests with :infinite?, answered with
just the next rows; no :rows-url, no loading
- :hx-target the container the handler re-renders, e.g. "#orders"
- :hx-swap default "outerHTML"
- :columns [{:field :label :class :sortable? (default true)
:filter {:placeholder :options}}]
- :rows rendered [:tr ...] rows
- :table-query {:sort :dir :page :page-size :search}
- :filters the parsed filters, kept by every control
- :total-count needed by :infinite?, with :rows-url
- :head-before, :head-after seqs of extra [:th] cells, e.g. a select-all box
- :colgroup, :tfoot, :class passed through(encode-query-params m)Turn a string-keyed map into a URL-encoded query string. Nil values are omitted; a sequential value repeats its key.
Turn a string-keyed map into a URL-encoded query string. Nil values are omitted; a sequential value repeats its key.
(filter-input {:keys [name value label placeholder options url hx-target hx-swap
hx-include push-url? attrs]
:or {hx-swap "outerHTML" hx-include "this" push-url? true}})An input that re-queries the table as the user types (a select, with :options [[value label] ...], when it changes) and pushes the URL.
opts:
An input that re-queries the table as the user types (a select, with :options [[value label] ...], when it changes) and pushes the URL. opts: - :name, :value, :label (aria-label), :placeholder, :options - :url the list URL to request, carrying the state to keep - :hx-target the table container selector - :hx-swap default "outerHTML" - :hx-include other inputs to send along, default "this" - :push-url? default true; false leaves the address bar alone - :attrs merged last, for classes or a different :type
(grouped-rows items {:keys [group-of row n-cols none-label]})items as (row item) under a heading row per group group-of names,
groups by name, items in their order; none-label heads the nil group,
last.
`items` as `(row item)` under a heading row per group `group-of` names, groups by name, items in their order; `none-label` heads the nil group, last.
(hidden-inputs params)A hidden input per value of a string-keyed param map, a sequential value
repeating its key: the table state a form or hx-include sends along.
A hidden input per value of a string-keyed param map, a sequential value repeating its key: the table state a form or `hx-include` sends along.
(infinite-rows rows next-url)rows with the last one loading next-url once scrolled into view: the
handler answers with the next page's rows, which go in after it, the last
of them carrying the page after that. No next-url, no loading.
`rows` with the last one loading `next-url` once scrolled into view: the handler answers with the next page's rows, which go in after it, the last of them carrying the page after that. No `next-url`, no loading.
(list-body {:keys [id url columns rows table-query filters empty empty-filtered
clear-label]})A data-table list in the container id its controls re-render, with a
sort select for narrow screens, or what to say when it is empty: empty,
or with a search or filters, empty-filtered and a link to url clearing
them. Holds the sort for controls outside it to send along.
A `data-table` list in the container `id` its controls re-render, with a sort select for narrow screens, or what to say when it is empty: `empty`, or with a search or filters, `empty-filtered` and a link to `url` clearing them. Holds the sort for controls outside it to send along.
(list-row {:keys [href attrs columns cells open-label]})A data-table row opening href on a click: its cells under columns,
then a chevron link named open-label. attrs add to the row's.
A `data-table` row opening `href` on a click: its `cells` under `columns`, then a chevron link named `open-label`. `attrs` add to the row's.
(list-url path table-query filters)path with the table state and filters as its query string, blank ones
left out, so the default view is the bare path.
`path` with the table state and filters as its query string, blank ones left out, so the default view is the bare path.
(next-page-url path table-query filters total-count)The URL of the page after table-query's, or nil on the last page.
The URL of the page after `table-query`'s, or nil on the last page.
(pagination {:keys [table-query total-count base-url push-url-base push-url?
hx-target hx-swap extra-params]
:or {hx-swap "outerHTML" push-url? true}})Render pagination controls for a table.
Shows page numbers with ellipsis, first/last jump, prev/next arrows, and a 'Showing X-Y of Z' summary.
opts:
sortable-thReturns nil when a single page is sufficient.
Render pagination controls for a table. Shows page numbers with ellipsis, first/last jump, prev/next arrows, and a 'Showing X-Y of Z' summary. opts: - :table-query normalized TableQuery map - :total-count total number of items - :base-url base URL for hx-get links (e.g. "/web/users") - :hx-target HTMX target selector - :hx-swap default "outerHTML"; see `sortable-th` - :push-url-base optional path used for browser URL updates (defaults to :base-url) - :push-url? default true; false leaves the address bar alone - :extra-params map of additional query params (filters, etc.) Returns nil when a single page is sufficient.
(parse-filter-params params)The filters[f][op|value|min|max|values][] params of a query string as
{:f {:op :eq :value "x"}}, :op defaulting to :eq as search-filters->params
writes it. Blank values are kept; see parse-table-params.
The `filters[f][op|value|min|max|values][]` params of a query string as
{:f {:op :eq :value "x"}}, :op defaulting to :eq as `search-filters->params`
writes it. Blank values are kept; see `parse-table-params`.(parse-table-params params)(parse-table-params params {:keys [sortable max-page-size keep-blank-filters?]})The table state in a Ring query-params map: {:sort :dir :page :page-size :search :filters}, each key only when present and valid.
opts:
:dir is :asc or :desc (sort-dir is accepted too).
The table state in a Ring query-params map: {:sort :dir :page :page-size
:search :filters}, each key only when present and valid.
opts:
- :sortable set of sortable field keywords; any other :sort is dropped
- :max-page-size upper bound for :page-size
- :keep-blank-filters? keep filters with no value, which a filter form
sends for its untouched inputs; dropped by default
:dir is :asc or :desc (`sort-dir` is accepted too).(query-rows rows {:keys [search sort dir]} {:keys [search-text sort-keys]})A list held in memory, searched and sorted as table-query says: the rows
whose (search-text row) holds every word of :search, ignoring case, by
((get sort-keys (:sort table-query)) row) in :dir, nil last. A :sort not
in sort-keys keeps the order given.
A list held in memory, searched and sorted as `table-query` says: the rows whose `(search-text row)` holds every word of :search, ignoring case, by `((get sort-keys (:sort table-query)) row)` in :dir, nil last. A :sort not in `sort-keys` keeps the order given.
(search-filters->params filters)Convert parsed search/filter map back into a string-keyed param map. A
filter spec map goes back in the filter bar's filters[f][op] format,
which is what the handlers parse.
Convert parsed search/filter map back into a string-keyed param map. A filter spec map goes back in the filter bar's `filters[f][op]` format, which is what the handlers parse.
(sort-select {:keys [url hx-target table-query filters columns]})Field and direction selects that re-sort a data-table, back to page one:
for a narrow screen, where rows are cards and the sortable headers hidden.
Takes data-table's :url, :hx-target, :table-query, :filters and :columns.
Nil when no column is sortable.
Field and direction selects that re-sort a `data-table`, back to page one: for a narrow screen, where rows are cards and the sortable headers hidden. Takes `data-table`'s :url, :hx-target, :table-query, :filters and :columns. Nil when no column is sortable.
(sortable-th {:keys [label field current-sort current-dir base-url push-url-base
_page page-size hx-target hx-swap hx-push-url?
extra-params]
:or {hx-swap "outerHTML"}})Reusable sortable table header cell.
opts:
Behaviour:
Reusable sortable table header cell.
opts:
- :label string label to display
- :field keyword used as :sort in TableQuery
- :current-sort current :sort from TableQuery
- :current-dir current :dir from TableQuery
- :base-url base path (e.g. "/web/users")
- :page current page (integer)
- :page-size current page-size (integer)
- :hx-target HTMX target selector (string)
- :hx-swap default "outerHTML": the handler returns the target element
itself. Pass "innerHTML" if it returns only the contents.
- :hx-push-url? bool, default true
- :push-url-base optional path used for browser URL updates (defaults to :base-url)
- :extra-params map of additional query params (keyword/string keys)
Behaviour:
- Clicking toggles :dir between :asc and :desc for the same :field.
- When changing sort field or direction, page is reset to 1.
(table-query->params {:keys [sort dir page page-size search]})Convert a TableQuery map into a string-keyed param map for query strings.
Convert a TableQuery map into a string-keyed param map for query strings.
(toolbar-search {:keys [id placeholder label] :as opts})A list toolbar's search box: a filter-input (same opts, :id its input's
id) behind the search icon.
A list toolbar's search box: a `filter-input` (same opts, :id its input's id) behind the search icon.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |