So… After some thinking, and some other time consuming IRL stuff, I finally got around to coding something. The prerequisite of the following script is that your TABLE
query produces a table where the first column is the tag, and the other columns are whatever they are. This version does not hide the tags, as per your example you only want to expand three levels of tags, and some of your examples have four levels of tags.
Fair warning: My test query is idiotic, and doesn’t have any useful values for the two other columns. It’s the literal text of ex 1
and ex 2
for all rows! 
So here is the query:
```dataviewjs
const expandLevels = 3 // How many levels of subtags to expand
const startHeaderLevel = 2 // Starting header level for first tag level
const consoleDebug = false // Set to true, if you want debug in console
function clog(args) { if ( consoleDebug ) console.log(...args) }
// In the following, replace the TABLE query with some query which lists
// nested tags in the first column, and have other columns...
const result = await dv.query(`
TABLE WITHOUT ID myTag, "ex 1" as someText, "ex 2" as anotherText
FLATTEN list(
"#elem/dad/death/change",
"#elem/dad/death/life",
"#elem/dad/gifts",
"#scene/death/life",
"#no/idea",
"#my/idea"
) as myTag
WHERE file.name = this.file.name
`)
if ( result.successful ) {
const values = result.value.values
clog("\n\n\n\n*** New run***\n")
// Define variables to be used to keep track of previous and
// current tags, and which new headers or rows to output
let prevTag = [],
currTag = [],
newHeaders = [],
sectionRows = [],
buildHeaders
// Loop every value of the table
for (let row of values) {
currTag = row[0].slice(1).split("/")
clog(currTag)
// Reset running variables
newHeaders = []
buildHeaders = false
clog("\nprevTag: ", prevTag)
currTag.forEach((subTag, i) => {
// if current sub tag is different from previous tag at the
// same level, then build new headers from this level until
// we expanded enough levels, or run out of subtags
clog("subtags: ", i, subTag)
clog("prevTag[i]: ", prevTag[i])
// Assuming we're not already building headers, then detect
// whether tags at this level differs, or didn't exist. Both
// indicate that we need to build new headers
if ( !buildHeaders ) {
if ( prevTag && prevTag[i] ) {
buildHeaders = subTag != prevTag[i]
} else {
buildHeaders = true
}
}
// If needed, push the new header onto the list
if ( buildHeaders && i < expandLevels )
newHeaders.push([i, currTag.slice(0, i + 1).join("/")])
})
// currTag changed, so we've got some new headers to output
if ( newHeaders.length > 0 ) {
// Before the new headers, output previous sections rows ...
if ( sectionRows.length > 0 ) {
// If you want to preserve table headers, use result.value.headers,
// or use [] to remove headers from table.
dv.table([], sectionRows)
sectionRows = []
}
// ... and then output the new headers
for (let header of newHeaders)
dv.header(startHeaderLevel + header[0], header[1])
}
// Store this row, and current tag for next iteration
prevTag = currTag
sectionRows.push(row)
}
// Output remaining rows, given no new headers lately
if ( sectionRows.length > 0 ) {
// NB! If changing the header a few lines higher, then change this too!
dv.table([], sectionRows)
}
} else
dv.paragraph("~~~~\n" + result.error + "\n~~~~")
```
And this produces the following output:
As can be seen, it builds the headers whenever it sees a change on the same (or higher) level, and it produces a table for each time the header changes.
However, since we don’t have proper control over the column widths, there is no coherent columns when doing it this way. If you want, you can add column headers (for each section), by following instructions in the code and changing: dv.table([], ... )
, into dv.table(result.value.headers, ... )
in two places in the script.
The output image uses Minimal theme with colorful headings, but they’re at level H2 through H4.
I’ve seen this, and I’m not sure if you countered for the more than three levels as shown in the first variant. And I didn’t read your query well enough to actually see that it had only a file.link
as the column.
I might look into another variant, but I’m entering a busy period again, so I’m not sure I’ve got the time for it (within the next few days). But an idea if only having a file link, would be to present the related file links for any given section as a list, instead of a table. This would also solve the column width issue, but it would also “loose” the 4th tag level information.
Also note that in any case these headers are still not collapsible due to how dataview renders headers, and I’ve not found a way around that. Yet.