@gjirafatech/gj-tree-select
v1.0.2
Published
Hierarchical multi-select dropdown with tree connectors for Vue 2
Readme
@gjirafatech/gj-tree-select
A hierarchical multi-select dropdown with tree connector lines for Vue 2.
Works with any flat data — folders, channels, categories, departments — you provide a dataAdapter and the component builds the tree.
Install
npm install @gjirafatech/gj-tree-selectQuick Start
Global registration
import Vue from 'vue'
import GjTreeSelect from '@gjirafatech/gj-tree-select'
Vue.use(GjTreeSelect)Local registration
import { GjTreeSelect } from '@gjirafatech/gj-tree-select'
export default {
components: { GjTreeSelect }
}Basic Usage
<template>
<GjTreeSelect
v-model="selectedIds"
:items="folders"
placeholder="Select folder"
/>
</template>
<script>
export default {
data() {
return {
selectedIds: [],
folders: [
{ id: 1, parentId: 0, name: 'Sports' },
{ id: 2, parentId: 0, name: 'News' },
{ id: 3, parentId: 1, name: 'Football' },
{ id: 4, parentId: 1, name: 'Basketball' },
{ id: 5, parentId: 3, name: 'Premier League' },
]
}
}
}
</script>Custom Icons (Scoped Slots)
The component renders fallback SVG icons by default. Override them with scoped slots:
<GjTreeSelect v-model="selectedIds" :items="folders" placeholder="Select folder">
<!-- Custom node icon -->
<template #node-icon="{ node, isSelected }">
<GjIcon name="FolderOutline" size="20" />
</template>
<!-- Custom checkbox -->
<template #check-icon="{ node, isSelected }">
<GjIcon
:name="isSelected ? 'CheckButtonSquareEnabledFilled' : 'CheckButtonSquareDisabled'"
size="16"
/>
</template>
<!-- Custom chevron -->
<template #chevron-icon="{ isOpen }">
<GjIcon name="ArrowDown" size="16" />
</template>
<!-- Custom tag remove -->
<template #tag-remove-icon="{ tag }">
<GjIcon name="Close" size="16" />
</template>
</GjTreeSelect>Different Data Shapes (dataAdapter)
Your API returns channelId, parentChannelId, title? No problem:
<GjTreeSelect
v-model="selectedChannels"
:items="channels"
:data-adapter="{
idKey: 'channelId',
parentIdKey: 'parentChannelId',
nameKey: 'title',
rootParentId: null,
}"
placeholder="Select channel"
>
<template #node-icon>
<GjIcon name="Broadcast" size="20" />
</template>
</GjTreeSelect>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value (v-model) | Array | [] | Selected IDs. |
| items | Array | [] | Flat array of items (any shape). |
| data-adapter | Object | { idKey: 'id', parentIdKey: 'parentId', nameKey: 'name', rootParentId: 0 } | Maps your data fields. |
| placeholder | String | 'Select...' | Placeholder text. |
| max-visible-tags | Number | 2 | Tags before +N overflow. |
| searchable | Boolean | true | Enable search filtering. |
| disabled | Boolean | false | Disable the component. |
| show-select-all | Boolean | true | "Select all" on root nodes. |
| select-all-label | String | 'Select all' | Label for select-all. |
| deselect-all-label | String | 'Deselect' | Label for deselect-all. |
| empty-text | String | 'No items available' | Empty state text. |
| connector-geometry | Object | See below | SVG connector pixel constants. |
| theme | Object | {} | CSS custom-property overrides. |
Default Connector Geometry
{
laneWidth: 22,
rowHeight: 32,
rowCenterY: 16,
elbowRadius: 8,
horizontalEndGap: 2,
verticalOverflow: 10,
parentEntryOverflow: 8
}Events
| Event | Payload | Description |
|---|---|---|
| input | Array<id> | Selection changed (v-model). |
| open | — | Dropdown opened. |
| close | — | Dropdown closed. |
Scoped Slots
| Slot | Props | Description |
|---|---|---|
| node-icon | { node, isSelected } | Icon before label in each row. |
| check-icon | { node, isSelected } | Checkbox icon on the right. |
| chevron-icon | { isOpen } | Chevron in the control bar. |
| tag-remove-icon | { tag } | Remove button inside tag pills. |
| tag | { tag, remove } | Full override of a tag pill. |
Theming (CSS Custom Properties)
Pass a theme object to override any CSS variable:
<GjTreeSelect
:theme="{
'--gj-ts-control-border-active': '#3A81F6',
'--gj-ts-row-selected-bg': '#ECF3FF',
'--gj-ts-select-all-color': '#3A81F6',
'--gj-ts-check-active-color': '#3A81F6',
}"
/>Available CSS Variables
| Variable | Default | What it styles |
|---|---|---|
| --gj-ts-control-bg | #ffffff | Control background |
| --gj-ts-control-border | #EDEFF3 | Control border |
| --gj-ts-control-border-active | #F4B261 | Control border when open |
| --gj-ts-control-radius | 0.25rem | Control border radius |
| --gj-ts-control-min-height | 35px | Control min height |
| --gj-ts-tag-bg | #F6F8F9 | Tag pill background |
| --gj-ts-tag-color | #030F28 | Tag pill text |
| --gj-ts-tag-radius | 20px | Tag pill radius |
| --gj-ts-tag-max-width | 140px | Tag pill max width |
| --gj-ts-placeholder-color | #B5C0CE | Placeholder text |
| --gj-ts-menu-border | #DADFE7 | Dropdown border |
| --gj-ts-menu-radius | 6px | Dropdown radius |
| --gj-ts-menu-shadow | 0 4px 12px ... | Dropdown shadow |
| --gj-ts-menu-max-height | 340px | Dropdown max height |
| --gj-ts-menu-bg | #ffffff | Dropdown background |
| --gj-ts-row-height | 32px | Tree row height |
| --gj-ts-row-radius | 6px | Tree row radius |
| --gj-ts-row-hover-bg | #F6F8F9 | Row hover background |
| --gj-ts-row-selected-bg | #FDE9D3 | Row selected background |
| --gj-ts-row-gap | 8px | Gap between rows |
| --gj-ts-label-color | #030F28 | Label text color |
| --gj-ts-label-font-size | 0.875rem | Label font size |
| --gj-ts-select-all-color | #F4B261 | "Select all" button color |
| --gj-ts-check-color | #A3B0C2 | Unchecked checkbox color |
| --gj-ts-check-active-color | #F4B261 | Checked checkbox color |
| --gj-ts-connector-color | #C9CDD3 | Connector line color |
| --gj-ts-connector-width | 1 | Connector line width |
License
MIT
