Columns
This page is about the Column row values the table works with, not about
writing column definitions. For that, see
Column Definitions.
It is the port of TanStack's Columns guide. The difference worth stating
first: in TanStack a column def is a plain object and the table turns it
into a column instance with methods on it. Here there is only one thing.
Table.column returns a Column row, the
with* builders return a Column row, and that is what the table reads. No
construction step happens in between.
Column row is opaque, so you read it through functions.
Where to get columns from
Header and cell objects
If you are rendering markup, you probably want headers or
cells rather than columns. Neither of them carries a column
though: a header carries headerColumnId and a cell carries columnId, so
going the other way is a lookup:
headerColumn : Table.Header Person -> Maybe (Table.Column Person)
headerColumn header =
Table.findColumn config (Table.headerColumnId header)
Column list functions
| TanStack | elm-table |
|---|---|
table.getColumn(id) |
findColumn |
table.getAllColumns() |
Config.columns, the record field you built |
table.getAllFlatColumns() |
allColumns |
table.getAllLeafColumns() |
leafColumns, then orderColumns |
table.getVisibleFlatColumns() |
visibleFlatColumns |
table.getVisibleLeafColumns() |
visibleLeafColumns |
column.columns |
columnColumns |
column.getFlatColumns() |
columnFlatColumns |
column.getLeafColumns() |
columnLeafColumns |
table.getStartLeafColumns() |
leftLeafColumns |
table.getCenterLeafColumns() |
centerLeafColumns |
table.getEndLeafColumns() |
rightLeafColumns |
table.getStartVisibleLeafColumns() |
leftVisibleLeafColumns |
table.getCenterVisibleLeafColumns() |
centerVisibleLeafColumns |
table.getEndVisibleLeafColumns() |
rightVisibleLeafColumns |
The ones that only walk the column tree take just the Config. The ones that
depend on order, visibility, or pinning take the State as well.
allColumns is the flattened tree: every column, group columns included,
each group before its children. TanStack's getAllColumns() is the
unflattened tree, which here is simply the columns field of your Config,
since Config is a plain record.
leafColumns is in definition order. TanStack's getAllLeafColumns() also
applies the table order, which is orderColumns
here.
config : Table.Config Person
config =
Table.config
[ Table.display "select"
, Table.group "name"
[ Table.column "firstName" (.firstName >> Value.String)
|> Table.withHeader "First"
, Table.column "lastName" (.lastName >> Value.String)
|> Table.withHeader "Last"
]
|> Table.withHeader "Name"
, Table.column "salary" (.salary >> Value.Number)
|> Table.withHeader "Salary"
|> Table.withSize 120
]
columnTree : List String
columnTree =
Table.allColumns config
|> List.map (\col -> String.repeat (Table.columnDepth col) " " ++ columnLabel col)
findColumn searches that same list,
so group columns are found too:
salaryWidth : Float
salaryWidth =
Table.findColumn config "salary"
|> Maybe.map (Table.columnSize config)
|> Maybe.withDefault 0
The tree and the leaf list
This is the distinction to get right, because the two lists have different lengths and different uses.
The tree is what you wrote. allColumns walks it, columnColumns gives
one group's children, columnDepth says how deep a column sits, and
columnParentId points back up.
childLabels : Table.Column Person -> List String
childLabels col =
List.map columnLabel (Table.columnColumns col)
parentLabel : Table.Column Person -> String
parentLabel col =
Table.columnParentId col
|> Maybe.andThen (Table.findColumn config)
|> Maybe.map columnLabel
|> Maybe.withDefault "(top level)"
The leaf list is the columns that actually produce cells. Group columns
have no accessor and no cells, so they are not in it.
columnLeafColumns is the
per-column version: the leaves under one column, or the column itself when it
is already a leaf.
leafIds : List String
leafIds =
List.map Table.columnId (Table.leafColumns config)
coveredLeafIds : Table.Column Person -> List String
coveredLeafIds col =
List.map Table.columnId (Table.columnLeafColumns col)
Which list to render
- Body cells:
visibleLeafColumns, or better, the cells of the row, which are already in that order.
renderedColumns : Table.State -> List (Table.Column Person)
renderedColumns state =
Table.visibleLeafColumns config state
- Header cells: neither. Use
headerGroups, which turns the column tree into header rows with the rightcolspanandrowspan. See Header Groups. - A column visibility menu:
allColumns, so the user sees the group columns and the already-hidden ones.visibleFlatColumnsis the same list minus the hidden columns, which is what you want for a legend or an export, not for a menu that turns columns back on.
viewColumnMenu : Table.State -> Html Msg
viewColumnMenu state =
ul []
(Table.allColumns config
|> List.map
(\col ->
li []
[ label []
[ input
[ type_ "checkbox"
, checked (Table.columnIsVisible state col)
, onClick (ToggleColumn col)
]
[]
, text (columnLabel col)
]
]
)
)
Column objects
| TanStack | elm-table |
|---|---|
column.id |
columnId |
column.columnDef.header |
columnHeader |
column.columnDef.footer |
columnFooter |
column.depth |
columnDepth |
column.columns |
columnColumns |
column.parent |
columnParentId |
column.accessorFn |
columnAccessor |
column.getSize() |
columnSize |
column.columnDef.minSize |
columnMinSize |
column.columnDef.maxSize |
columnMaxSize |
column.columnDef |
none, the column is the definition |
Column ids
Every column has an id, and you always write it yourself:
Table.column "firstName" .... There is no accessorKey to derive one from,
because an accessor here is a function rather than a key path, and no header
to fall back on. Ids must be unique across the whole table, group columns
included.
Column defs
column.columnDef has no counterpart. The Column row value is the
definition, built by Table.column, Table.group, or Table.display and
then piped through with* builders. So columnHeader reads back what
withHeader set, and so on.
columnHeader and columnFooter are Maybe String, since both builders are
optional. Most views fall back to the column id:
columnLabel : Table.Column Person -> String
columnLabel col =
Maybe.withDefault (Table.columnId col) (Table.columnHeader col)
Nested grouped column properties
columnColumns: the children of a group column, empty on an accessor or display column.columnDepth:0at the top level, stamped byTable.groupwhen the column is nested.columnParentId: the id of the group column above,Nothingat the top level. TanStack stores the parent column itself; here it is an id, so pair it withfindColumn.columnFlatColumns: one column and everything below it, the column itself first.
Accessors and sizes
columnAccessor gives back the
function you passed to Table.column, or Nothing for a group or display
column. That is the way to tell the three kinds apart:
hasAccessor : Table.Column Person -> Bool
hasAccessor col =
Table.columnAccessor col /= Nothing
columnSize,
columnMinSize, and
columnMaxSize take the Config
because an unset size falls back to Config.defaultColumn, which defaults to
150, 20, and 9007199254740991 pixels. They are the static sizes. For
the rendered width, which also accounts for State.columnSizing, use
getColumnSize. See
Column Sizing.
Ordering a column list
orderColumns puts any column list
into table order: State.columnOrder first, unlisted columns behind the
listed ones, then the grouped-column rules.
orderedLeafColumns : Table.State -> List (Table.Column Person)
orderedLeafColumns state =
Table.leafColumns config
|> Table.orderColumns config state
orderGroupedColumns applies
only Config.groupedColumnMode to a leaf column list, moving the grouped
columns to the front (the default), removing them, or leaving the list alone.
groupedFirst : Table.State -> List (Table.Column Person)
groupedFirst state =
Table.leafColumns config
|> Table.orderGroupedColumns config state
visibleLeafColumns already runs the ordering, so reach for these two only
when you are building a list of your own. Note that visibleLeafColumns is
not pin-ordered, matching TanStack: the pin split happens in
visibleCells and in the header
functions. See Column Ordering and
Column Pinning.
More column APIs
The per-feature column queries are with their features:
columnIsVisible and
columnCanHide in
Column Visibility,
columnIsPinned and
columnCanPin in
Column Pinning,
getCanSort in
Sorting,
getCanFilter in
Column Filtering,
getCanGroup in
Grouping.
Several of those take a column id rather than a Column row, because they
only read the State. Check the signature in the
module reference.
Column rendering
Do not render headers or cells from columns. Use headers and cells, which carry the spans, the order, and the values. Columns are for lists of columns: a visibility menu, a grouping picker, a settings panel.