Is there a way to create column filter methods that can function as an Input with viewof?

In the notebook below I’ve outlined my question. I’ll repeat it here but the basic idea is that I want to add dropdown filters to Inputs.table or something like it.

Question

Is there any way to add filters to the column header? So for example, I’d love a drop down where Gender has unique values for (“Male”, “Female”) and I could apply a filter to the whole tbl (say all “Male”).

Note

I know that one can create a data table (see below). Those are amazing but I want to implement this in code for re-use in quarto and observable framework.

Here is the notebook:

Thoughts?

Sam

That’s not supported in Inputs.table, but you can create each of the drop-downs individually, then create a table downstream.

For example:

viewof year = Inputs.select([null, 1960, 1961, 1962, …])

viewof city = Inputs.select([null, "Boston", "Singapore", …])

filtered = data
           .filter((d) => year === null || d.year === year)
           .filter((d) => city === null || d.city === city)

Inputs.table(filtered)

In summary tables by Fil · Pull Request #1120 · observablehq/framework · GitHub we have a prototype to do this in a more integrated way, but it’s far from being usable.

Ah thanks for the reply. Your suggestion makes complete sense but it sort of the opposite of what I am trying to achieve. Ultimately trying to provide a UI piece that limits a large number of values in Inputs.select by having a top level table for selection.

I did think based on this that I might be able to use Inputs.bind like this:

Inputs.bind(
  Inputs.table(distinctTable, {columns: ["Gender"]}),
  Inputs.table(distinctTable, {columns: ["Name"]})
)

but reading the docs a bit closer I realized that that’s not how it is meant to be used.

But I am wondering if this approach could work generally where one makes several single column tables and then uses the selection values. I get a bit confused on how to align Inputs horizontal but is it possible to put line up several Inputs.table objects horizontally so that it looks like one table but each column ends up with an input check mark?

One of the challenges of filtering a table is that you lose the current selection when the table rerenders. Even if you reassign the previous value it will still discard items that are filtered out.

I put together a guide for a helper that I had created a while back:

This is perfect. Thank you! I modified the template function like so:

function filterGrid(inputs) {
  const scope = DOM.uid().id;
  return htl.html`<div class=${scope}>${Object.values(inputs)}
    <style>
      .${scope} { 
        display: flex; 
        flex-wrap: wrap; 
        gap: 0.5ch; 
        font-size: 0.8em; 
      }
      .${scope} form, .${scope} form > * { 
        width: fit-content !important margin-bottom: 1em;
      }
  `;
}