GrTreeSections
A tree whose top level becomes a section heading instead of a node.
Overview
When to take it
- the roots are categories, not items — settings, access rights, directories: selecting the heading itself is pointless, while naming it is necessary;
- two levels of content — under each heading an ordinary tree whose depth is no longer about headings;
- the sections need weight in the structure of the page — the heading gets a real level
(
h2…h6) and lands in the outline of the document; - a counter at the heading — how many nodes are in the section, without expanding.
When to take something else
| Need | Take |
|---|---|
| The top level is a node like the rest | GrTree |
| Markup of your own and roles of your own entirely | useTree |
| The tree is in a selection panel rather than on the screen | GrTreeSelect |
| Sections of which one is open | GrCollapse |
| A table of contents of the page with a highlight by scroll | GrScrollSpy |
Playground controls come from the API, not from hand
Loading…
0 changed· state is in the URL
<GrTreeSections :data="data" />Examples 3 each with a live demo and its code
The sidebar of an API reference
Resources are categories, not endpoints: choosing «Invoices» itself means nothing, but it needs a name. With
heading-levelthe roots become real headings of the level the page needs — here 4, under the example’s own title — and the page outline lists them; under each sits an ordinary tree with its own keyboard ring — Tab moves between groups, the arrows inside one.v-model:current-keyis one for all groups; the default slot adds the HTTP method.Finalize an invoicePOST /v1/invoices/{id}/finalizeLocks the lines of a draft and assigns the invoice number. A finalized invoice can be voided, not edited.Which events send an email
show-checkboxworks as in the tree, but each group counts its own parents and never touches its neighbours, so all groups share onev-model:checked-keyswithout losses. Theheadingslot replaces the label of a group with a summary of what is on in it.Email notifications4 events send an email Billing2 of 4 on
Invoice issuedPayment failedFirst attemptFinal attemptRenewal in 7 daysSecurity2 of 2 on
Sign-in from a new deviceAPI key createdTeam0 of 2 on
Member joinedMember removedSources in a query editor
A dense rail:
size="xs"with a narrowerindentkeeps three levels inside 15rem, andshow-countputs the number of top-level entries next to each source without opening it.node-clickhands over the row and its node, and the parent schema completes the table name in the query.Untitled queryselect * from billing.invoices limit 100
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
datarequired | T[] | — | The data of an ordinary tree. The roots become headings, their children become trees. |
nodeKey | "id" | Extract<keyof T, string> | undefined | "id" as never | The field with the key of a node. The keys are unique across all groups at once: the current node and the checks are kept in one set by them. `id` by default. |
props | GrTreePropsMap | undefined | undefined | The names of the fields in the data: `children`, `label`, `isLeaf`. `children` and `label` by default. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | The size of the rows of all groups, as in `GrTree`. Unset — from `GrConfigProvider`, otherwise `md`. |
headingLevel | 2 | 3 | 4 | 5 | 6 | undefined | 3 | The heading level of a group to fit the structure of the page. |
showCount | boolean | undefined | false | Show the number of first-level nodes in a group. |
showCheckbox | boolean | undefined | false | Checkboxes at the nodes: a multiple choice on top of the groups. |
checkStrictly | boolean | undefined | false | Do not link the parents and the children: every node is checked on its own. |
branchLine | boolean | GrTreeBranchLine | undefined | undefined | The guide lines of the levels: `line` is a vertical per level, `elbow` adds an elbow to the row as well. `line` by default. |
indent | number | undefined | 0 | The step of the indent of a level in pixels. `0` (the default) means the value from the theme. |
defaultExpandedKeys | GrTreeKey[] | undefined | [] | The initial set of expanded nodes in all groups. A new array replaces the expansion entirely. |
currentKeyv-model | GrTreeKey | undefined | undefined | The current node (`v-model:currentKey`) — one for all groups. |
checkedKeysv-model | GrTreeKey[] | undefined | undefined | The checked keys of all groups in one list (`v-model:checkedKeys`). |
Slots
| Slot | Type | Description |
|---|---|---|
heading | { data: T; label: string; count: number; } | The heading of a group as a whole — instead of the label of the root node. |
default | { node: GrTreeNode<T>; data: T; } | A row inside a group, as in `GrTree`. |
Events
| Event | Signature | Description |
|---|---|---|
update:currentKey | (e: "update:currentKey", key: GrTreeKey | undefined): void | The current node has changed by a click or `Enter` in any of the groups (`v-model:currentKey`). |
update:checkedKeys | (e: "update:checkedKeys", keys: GrTreeKey[]): void | The checks have changed (`v-model:checkedKeys`): the checks of a group are merged with the checks of the other groups from `checkedKeys`; parents checked in a cascade are included too. |
nodeClick | (e: "nodeClick", data: any, node: GrTreeNode<any>): void | A node has been selected by a click or `Enter` and has become the current one — the row data and the node, as in `GrTree`. |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrTreeSectionsProps, GrTreeSectionsEmits, GrTreeSectionsInstance } from '@feugene/granularity/components/GrTreeSections'Filedist/types/components/GrTreeSections/GrTreeSections.vue.d.ts
interface GrTreeSectionsProps<TData extends object = any> {
data: TData[];
nodeKey?: GrTreeDataProps<TData>['nodeKey'];
props?: GrTreePropsMap;
size?: GrComponentSize;
headingLevel?: 2 | 3 | 4 | 5 | 6;
showCount?: boolean;
showCheckbox?: boolean;
checkStrictly?: boolean;
branchLine?: boolean | GrTreeBranchLine;
indent?: number;
defaultExpandedKeys?: GrTreeKey[];
currentKey?: GrTreeKey;
checkedKeys?: GrTreeKey[];
}interface GrTreeSectionsEmits {
(e: 'update:currentKey', key: GrTreeKey | undefined): void;
(e: 'update:checkedKeys', keys: GrTreeKey[]): void;
(e: 'nodeClick', data: any, node: GrTreeNode<any>): void;
}Filedist/types/components/GrTreeSections/config.d.ts
const grTreeSectionsConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrTreeSections">;Filedist/types/components/GrTreeSections/safelist.d.ts
const grTreeSectionsSafelist: string[];Filedist/types/components/GrTreeSections/index.d.ts
type GrTreeSectionsInstance = ComponentExposed<typeof GrTreeSectionsComponent>;Usage from the library prose
Inside there are several trees, not one with headings
That is not a detail of the implementation but a requirement of the pattern: role="tree" obliges
its children to be treeitem, and a heading between the rows either breaks the role or remains a
row and lies to a screen reader about what it is. Headings between separate trees are legal, and
each group declares itself — the name of the tree is taken from the caption of the heading.
Hence a consequence worth knowing in advance: each group has a keyboard ring of its own, and
Tab moves between them while the arrows walk inside one. That is right in substance — the groups
are independent — but differs from a single tree, where the arrows pass through the whole list.
One selection, the ticks add up
The selected node is one across all groups: the keys are unique, so the other groups simply will not find a foreign key among their own.
The ticks are collected as a union over the groups. They can be reduced to one list without losses precisely because the groups have no common parent: the inheritance inside each is computed on its own and does not affect the neighbours.
The limits
- the headings do not collapse. A heading is a heading, not a toggle; a collapsible section is
needed — that is
GrCollapsewith a tree inside; - deeper than three levels the device stops helping. The first level is taken by the heading, the second lies flat, and beyond that goes the ordinary staircase of indentation — and there are more headings than content.
Props in this example