Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
ee1b538
feat: initialize ember-table addon
rtablada Jun 29, 2026
8d5b7a8
chore: update build and package to tanstack
rtablada Jun 29, 2026
46c52cf
claude: initial use-table ember-table implementation
rtablada Jun 29, 2026
53ae208
feat: flex-render uses components
rtablada Jun 30, 2026
280ee4c
feat: fix the types around flex render
rtablada Jun 30, 2026
795379b
wip: initialize test-app for ember-table
rtablada Jun 29, 2026
d541253
feat: implement basic-external-state ember example
rtablada Jun 29, 2026
0cfc3bf
remove legacy directory gitkeeps
rtablada Jun 30, 2026
d6cda72
fix: use FlexRender components
rtablada Jun 30, 2026
27eaa7c
wip: working on ember with external state
rtablada Jul 2, 2026
7c0ec68
feat: working reactivity and use-table
rtablada Jul 2, 2026
c55c817
feat: for initial development internalize examples
rtablada Jul 2, 2026
b1ae417
example: kitchen sink
rtablada Jul 3, 2026
345b266
wip: removing example ember temporarily
rtablada Jul 3, 2026
9bf699b
chore: remove ember-cli legacy addon files
rtablada Jul 9, 2026
30c9d91
rebased pnpm-lock
rtablada Jul 9, 2026
03c31b4
test: add base test example
rtablada Jul 9, 2026
5566cdc
test: add reactivity and use-table tests
rtablada Jul 9, 2026
6544080
test: flex render test
rtablada Jul 9, 2026
5eb858d
claude: wrap state slices in proxy object
rtablada Jul 9, 2026
3944589
feat: test with ember create-atom
rtablada Jul 9, 2026
7cfac9a
claude: update value with compare
rtablada Jul 9, 2026
0ce015d
subscribe with ember
rtablada Jul 9, 2026
42a30c8
ref: move signals to own file
rtablada Jul 10, 2026
77b9ad6
chore: update use-state comment/type and lint fix
rtablada Jul 10, 2026
02129e1
chore: remove duplicate configs and move prettier to root
rtablada Jul 10, 2026
82c4977
lint: update to global prettier config
rtablada Jul 10, 2026
146c0be
wip: blank example app
rtablada Jul 10, 2026
e59512b
example: basic-table
rtablada Jul 10, 2026
d4258b1
example: basic-external-state
rtablada Jul 10, 2026
f1233b1
example: sorting
rtablada Jul 10, 2026
32770d0
example: filters
rtablada Jul 10, 2026
a7a5850
example: filters-faceted
rtablada Jul 10, 2026
c3300d9
example: filters-fuzzy
rtablada Jul 10, 2026
f1c6948
example: pagination
rtablada Jul 10, 2026
771e998
example: row-selection
rtablada Jul 10, 2026
4599712
example: expanding
rtablada Jul 10, 2026
21279dc
example: sub-components
rtablada Jul 10, 2026
d62c49a
example: row-pinning
rtablada Jul 10, 2026
d7d7fd3
example: grouping
rtablada Jul 10, 2026
a432ee8
example: editable
rtablada Jul 10, 2026
4981377
example: row-dnd
rtablada Jul 10, 2026
ea0099e
example: column-groups
rtablada Jul 10, 2026
45a341d
example: column-visibility
rtablada Jul 10, 2026
a1edea2
example: column-ordering
rtablada Jul 10, 2026
5aef2c6
example: column-pinning
rtablada Jul 10, 2026
c326eec
example: column-pinning-sticky
rtablada Jul 10, 2026
8a7a761
example: column-pinning-split
rtablada Jul 10, 2026
1b8c4e2
example: column-sizing
rtablada Jul 10, 2026
ce9ba5e
example: column-resizing
rtablada Jul 10, 2026
1bf9cb7
example: column-resizing-performant
rtablada Jul 10, 2026
d0d2bf3
example: custom-plugin
rtablada Jul 10, 2026
5351ea0
example: remote-data
rtablada Jul 10, 2026
c97250d
example: kitchen-sink
rtablada Jul 10, 2026
4cafd76
example: basic-external-atoms
rtablada Jul 10, 2026
57c768f
chore: remove the ember demo-app
rtablada Jul 10, 2026
0d99c1f
fix: run lint fix
rtablada Jul 10, 2026
707877f
fix: remove unused dev deps and update order of package deps
rtablada Jul 10, 2026
54e1c49
ref: change `@args` to `@optins`
rtablada Jul 11, 2026
e6e401c
fix: sherif
rtablada Jul 11, 2026
1a7096b
fix: lints
rtablada Jul 11, 2026
eeb6aa4
fix: lints
rtablada Jul 11, 2026
c41284f
fix: knip config
rtablada Jul 11, 2026
f8c479e
ci: apply automated fixes
autofix-ci[bot] Jul 11, 2026
94de400
generate ember api reference docs, add smoke tests, fix wrong api met…
KevinVandy Jul 11, 2026
629520b
add ember docs
KevinVandy Jul 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
97 changes: 97 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
{ "label": "Rendering components", "to": "framework/angular/guide/rendering" }
]
},
{
"label": "ember",
"children": [
{ "label": "Quick Start", "to": "framework/ember/quick-start" }
]
},
{
"label": "lit",
"children": [
Expand Down Expand Up @@ -121,6 +127,13 @@
{ "label": "Custom Plugins", "to": "framework/angular/guide/custom-features" }
]
},
{
"label": "ember",
"children": [
{ "label": "Table State", "to": "framework/ember/guide/table-state" },
{ "label": "Custom Plugins", "to": "framework/ember/guide/custom-features" }
]
},
{
"label": "lit",
"children": [
Expand Down Expand Up @@ -224,6 +237,26 @@
{ "label": "Virtualization", "to": "framework/angular/guide/virtualization" }
]
},
{
"label": "ember",
"children": [
{ "label": "Column Ordering", "to": "framework/ember/guide/column-ordering" },
{ "label": "Column Pinning", "to": "framework/ember/guide/column-pinning" },
{ "label": "Column Sizing", "to": "framework/ember/guide/column-sizing" },
{ "label": "Column Resizing", "to": "framework/ember/guide/column-resizing" },
{ "label": "Column Visibility", "to": "framework/ember/guide/column-visibility" },
{ "label": "Column Filtering", "to": "framework/ember/guide/column-filtering" },
{ "label": "Global Filtering", "to": "framework/ember/guide/global-filtering" },
{ "label": "Fuzzy Filtering", "to": "framework/ember/guide/fuzzy-filtering" },
{ "label": "Faceting", "to": "framework/ember/guide/column-faceting" },
{ "label": "Grouping", "to": "framework/ember/guide/grouping" },
{ "label": "Expanding", "to": "framework/ember/guide/expanding" },
{ "label": "Pagination", "to": "framework/ember/guide/pagination" },
{ "label": "Row Pinning", "to": "framework/ember/guide/row-pinning" },
{ "label": "Row Selection", "to": "framework/ember/guide/row-selection" },
{ "label": "Sorting", "to": "framework/ember/guide/sorting" }
]
},
{
"label": "lit",
"children": [
Expand Down Expand Up @@ -370,6 +403,12 @@
{ "label": "Angular API Reference", "to": "framework/angular/reference/index" }
]
},
{
"label": "ember",
"children": [
{ "label": "Ember API Reference", "to": "framework/ember/reference/index" }
]
},
{
"label": "react",
"children": [
Expand Down Expand Up @@ -473,6 +512,22 @@
{ "label": "injectTableContext", "to": "framework/angular/reference/functions/injectTableContext" }
]
},
{
"label": "ember",
"children": [
{ "label": "useTable", "to": "framework/ember/reference/functions/useTable" },
{ "label": "FlexRenderCell", "to": "framework/ember/reference/classes/FlexRenderCell" },
{ "label": "FlexRenderHeader", "to": "framework/ember/reference/classes/FlexRenderHeader" },
{ "label": "FlexRenderFooter", "to": "framework/ember/reference/classes/FlexRenderFooter" },
{ "label": "flexRenderComponent", "to": "framework/ember/reference/functions/flexRenderComponent" },
{ "label": "FlexRenderableSignature", "to": "framework/ember/reference/interfaces/FlexRenderableSignature" },
{ "label": "CellRenderableSignature", "to": "framework/ember/reference/interfaces/CellRenderableSignature" },
{ "label": "emberReactivity", "to": "framework/ember/reference/functions/emberReactivity" },
{ "label": "createAtom", "to": "framework/ember/reference/functions/createAtom" },
{ "label": "signal", "to": "framework/ember/reference/functions/signal" },
{ "label": "computed", "to": "framework/ember/reference/functions/computed" }
]
},
{
"label": "preact",
"children": [
Expand Down Expand Up @@ -875,6 +930,15 @@
{ "label": "Header Groups", "to": "framework/angular/examples/column-groups" }
]
},
{
"label": "ember",
"children": [
{ "label": "Basic (useTable)", "to": "framework/ember/examples/basic-table" },
{ "label": "Basic (External State)", "to": "framework/ember/examples/basic-external-state" },
{ "label": "Basic (External Atoms)", "to": "framework/ember/examples/basic-external-atoms" },
{ "label": "Header Groups", "to": "framework/ember/examples/column-groups" }
]
},
{
"label": "lit",
"children": [
Expand Down Expand Up @@ -1005,6 +1069,30 @@
{ "label": "Sorting", "to": "framework/angular/examples/sorting" }
]
},
{
"label": "ember",
"children": [
{ "label": "Kitchen Sink (All Features)", "to": "framework/ember/examples/kitchen-sink" },
{ "label": "Column Filters", "to": "framework/ember/examples/filters" },
{ "label": "Column Filters (Faceted)", "to": "framework/ember/examples/filters-faceted" },
{ "label": "Fuzzy Search Filters", "to": "framework/ember/examples/filters-fuzzy" },
{ "label": "Column Ordering", "to": "framework/ember/examples/column-ordering" },
{ "label": "Column Pinning", "to": "framework/ember/examples/column-pinning" },
{ "label": "Column Pinning (Split)", "to": "framework/ember/examples/column-pinning-split" },
{ "label": "Sticky Column Pinning", "to": "framework/ember/examples/column-pinning-sticky" },
{ "label": "Column Sizing", "to": "framework/ember/examples/column-sizing" },
{ "label": "Column Resizing", "to": "framework/ember/examples/column-resizing" },
{ "label": "Performant Column Resizing", "to": "framework/ember/examples/column-resizing-performant" },
{ "label": "Column Visibility", "to": "framework/ember/examples/column-visibility" },
{ "label": "Expanding", "to": "framework/ember/examples/expanding" },
{ "label": "Expanding Sub Components", "to": "framework/ember/examples/sub-components" },
{ "label": "Grouping", "to": "framework/ember/examples/grouping" },
{ "label": "Pagination", "to": "framework/ember/examples/pagination" },
{ "label": "Row Pinning", "to": "framework/ember/examples/row-pinning" },
{ "label": "Row Selection", "to": "framework/ember/examples/row-selection" },
{ "label": "Sorting", "to": "framework/ember/examples/sorting" }
]
},
{
"label": "lit",
"children": [
Expand Down Expand Up @@ -1188,6 +1276,15 @@
{ "label": "Row Drag & Drop", "to": "framework/angular/examples/row-dnd" }
]
},
{
"label": "ember",
"children": [
{ "label": "Custom Plugin", "to": "framework/ember/examples/custom-plugin" },
{ "label": "Editable data", "to": "framework/ember/examples/editable" },
{ "label": "Fetch API data (SPA / SSR)", "to": "framework/ember/examples/remote-data" },
{ "label": "Row Drag & Drop", "to": "framework/ember/examples/row-dnd" }
]
},
{
"label": "lit",
"children": [
Expand Down
168 changes: 168 additions & 0 deletions docs/framework/ember/guide/column-faceting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: Faceting (Ember) Guide
---

## Examples

Want to skip to the implementation? Check out these Ember examples:

- [Faceted Filters](../examples/filters-faceted)

### Faceting Setup

Here's how you set up your table to use faceting features. Adding the faceting feature enables the related APIs. Additionally, if using client-side faceting, you also need to set up `filteredRowModel` and `facetedRowModel` after their associated features because row model slots are type-checked.

```ts
import {
useTable,
tableFeatures,
columnFacetingFeature,
columnFilteringFeature,
createFacetedRowModel,
createFacetedUniqueValues,
createFacetedMinMaxValues,
createFilteredRowModel,
filterFns,
} from '@tanstack/ember-table'

const features = tableFeatures({
columnFacetingFeature,
columnFilteringFeature,
filteredRowModel: createFilteredRowModel(), // if using client-side filtering
facetedRowModel: createFacetedRowModel(), // if using client-side faceting
facetedUniqueValues: createFacetedUniqueValues(),
facetedMinMaxValues: createFacetedMinMaxValues(),
filterFns,
})

// inside your Glimmer component
table = useTable(() => ({
features,
columns,
data: this.data,
}))
```

## Faceting (Ember) Guide

Faceting is a feature that generates lists of values from your table's data, either for a single column (column faceting) or across the entire table (global faceting). For example, a list of unique values can be used as search suggestions in an autocomplete filter component, or a tuple of minimum and maximum values from a column of numbers can drive a range slider filter component. The same row models power both the per-column and table-wide APIs.

### Column Faceting Row Models

In order to use any of the column faceting features, add the `columnFacetingFeature` and the appropriate faceted row model factories to your features. Faceting exists to power filter UIs, so in practice you will also register the `columnFilteringFeature` and a `filteredRowModel`. Without a filtered row model, the faceted row models fall back to the pre-filtered rows and the facet values will not react to other columns' filters.

```ts
import {
useTable,
tableFeatures,
columnFacetingFeature,
columnFilteringFeature,
createFacetedRowModel,
createFacetedMinMaxValues,
createFacetedUniqueValues,
createFilteredRowModel,
filterFns,
} from '@tanstack/ember-table'

const features = tableFeatures({
columnFacetingFeature,
columnFilteringFeature,
filteredRowModel: createFilteredRowModel(), // facet values react to other columns' filters
facetedRowModel: createFacetedRowModel(), // required for faceting (other faceted row models depend on this)
facetedMinMaxValues: createFacetedMinMaxValues(), // if you need min/max values
facetedUniqueValues: createFacetedUniqueValues(), // if you need a list of unique values
filterFns,
})

// inside your Glimmer component
table = useTable(() => ({
features,
columns,
data: this.data,
}))
```

First, you must include the `facetedRowModel`. This row model will generate a list of values for a given column. If you need a list of unique values, include the `facetedUniqueValues` row model. If you need a tuple of minimum and maximum values, include the `facetedMinMaxValues` row model.

### Use Faceted Row Models

Once you have included the appropriate row models in your table options, you will be able to use the faceting column instance APIs to access the lists of values generated by the faceted row models.

```ts
// list of unique values for autocomplete filter
const autoCompleteSuggestions = Array.from(
column.getFacetedUniqueValues().keys(),
)
.sort()
.slice(0, 5000)
```

```ts
// tuple of min and max values for range filter
const [min, max] = column.getFacetedMinMaxValues() ?? [0, 1]
```

### Global Faceting

The same `columnFacetingFeature` and faceted row models also power table-wide (global) faceting. Where column faceting derives values from a single column, global faceting derives values across all columns, which is useful for populating a global filter's autocomplete suggestions or a global range slider. If your table also uses global filtering, register the `globalFilteringFeature` so global facet values react to the active global filter.

Use the global faceting table instance APIs to read the values:

```ts
const globalFacetedRows = table.getGlobalFacetedRowModel().flatRows
```

```ts
// list of unique values for autocomplete filter
const autoCompleteSuggestions = Array.from(
table.getGlobalFacetedUniqueValues().keys(),
)
.sort()
.slice(0, 5000)
```

```ts
// tuple of min and max values for range filter
const [min, max] = table.getGlobalFacetedMinMaxValues() ?? [0, 1]
```

### Custom (Server-Side) Faceting

Instead of using the built-in client-side faceting features, you can implement your own faceting logic on the server-side and pass the faceted values to the client-side. Supply custom `facetedUniqueValues` and `facetedMinMaxValues` factories in the features object. Each factory receives the table and a column ID and returns a thunk that resolves the faceted values. The column instance APIs (`column.getFacetedUniqueValues()` and `column.getFacetedMinMaxValues()`) will then return your server-provided values.

```ts
const features = tableFeatures({
columnFacetingFeature,
facetedUniqueValues: (_table, columnId) => () => {
const uniqueValueMap = new Map<string, number>()
//... populate from your server data for this columnId
return uniqueValueMap
},
facetedMinMaxValues: (_table, columnId) => () => {
//... read from your server data for this columnId
return [min, max]
},
})

// inside your Glimmer component
table = useTable(() => ({
features,
columns,
data: this.data,
//...
}))
```

The same factories also serve global faceting. Global faceting requests values with the internal `__global__` column ID, so you can branch on it inside the same `facetedUniqueValues` and `facetedMinMaxValues` factories on the features object to return table-wide facet values:

```ts
const features = tableFeatures({
columnFacetingFeature,
facetedUniqueValues: (_table, columnId) => () => {
if (columnId !== '__global__') return new Map() // per-column facets
return new Map(globalFacets.uniqueValues) // global facets
},
})
```

Alternatively, you don't have to put any of your faceting logic through the TanStack Table APIs at all. Just fetch your lists and pass them to your filter components directly.
Loading