Tinyrack

Tree Nav

Navigate expandable groups and typed destinations with tree keyboard semantics.

Build typed, expandable navigation with selected destinations and visible nested rails.

Contract

AxisContract
SelectionUse defaultValue for local selection or TRTreeNav.controlled with value and onValueChange for parent-owned selection.
ExpansioninitiallyExpanded seeds a group; TRTreeNavController reads or changes the live expanded set.
NestingEvery nested level adds a guide rail and indentation; groups containing the selected leaf use active emphasis.
PersistencepageStorageId restores expanded groups within the nearest PageStorage; selection ownership is unchanged.
Contentdescription adds a muted secondary line. leading and trailing stay aligned around the complete row. A group trailing replaces its chevron; a leaf can opt into a disclosure indicator after its trailing content.
ScaleOmit uiSize to follow TRUiDensityScope. Every size uses 8 logical pixels above and below the content. Standard density preserves the 40-pixel one-line leaf minimum; descriptions grow the row from its content.

Use TRTreeNav for an ordered collection or TRNavigationRow for one standalone destination. Tab follows reading order. Enter and Space activate the focused row, Up and Down move between tree rows, and the logical expand and collapse arrow keys follow text direction. Enabled rows show hover and pressed surfaces for pointer feedback. Disabled rows are skipped and ignore pointer and keyboard input.

Install

Add the package, then import its public library.

flutter pub add tinyrack_ui
import 'package:tinyrack_ui/tinyrack_ui.dart';

Playground

Usage

import 'package:material_ui/material_ui.dart';
import 'package:tinyrack_ui/tinyrack_ui.dart';

class DocsTree extends StatefulWidget {
  const DocsTree({super.key});

  @override
  State<DocsTree> createState() => _DocsTreeState();
}

class _DocsTreeState extends State<DocsTree> {
  String? currentPage = 'theming';

  @override
  Widget build(BuildContext context) => TRTreeNav<String>.controlled(
    value: currentPage,
    onValueChange: (value) => setState(() => currentPage = value),
    pageStorageId: 'docs-navigation',
    semanticLabel: 'Documentation',
    items: const [
      TRTreeNavGroup(
        value: 'guides',
        label: Text('GUIDES'),
        description: Text('Product documentation'),
        initiallyExpanded: true,
        children: [
          TRTreeNavLeaf(
            value: 'install',
            label: Text('Install'),
            description: Text('Add and configure the package'),
          ),
          TRTreeNavGroup(
            value: 'advanced',
            label: Text('ADVANCED'),
            initiallyExpanded: true,
            children: [
              TRTreeNavLeaf(value: 'plugins', label: Text('Plugins')),
              TRTreeNavLeaf(value: 'theming', label: Text('Theming')),
            ],
          ),
        ],
      ),
    ],
  );
}

Examples

Controlled documentation navigation permalink

Use a standalone row outside the collection, then keep nested tree expansion in PageStorage while the route changes.

API

TRNavigationRow properties

PropType / defaultPurpose
label, descriptionWidget, Widget? · label requiredRender the primary label and an optional muted secondary line.
leading, trailingWidget?, Widget? · nullAdd content around the label. The automatic disclosure indicator follows trailing content.
selected, enabledbool, bool · false, trueControl selected emphasis and whether the row can be activated.
onPressedVoidCallback? · nullActivate the destination. A row without a callback is non-actionable and omits its indicator.
uiSizeTRUiSize? · density defaultOverride the row and content scale supplied by TRUiDensityScope.

TRTreeNav properties

PropType / defaultPurpose
itemsList<TRTreeNavItem<T>> · requiredDefines the ordered groups and destinations.
value, defaultValueT?, T? · nullControl selection or initialize uncontrolled selection.
onValueChangeValueChanged<T?>? · nullReports an enabled leaf activation.
controllerTRTreeNavController<T>? · nullObserves selection and owns the expanded group set.
pageStorageId, semanticLabelObject?, String? · nullPersist expansion and name the navigation region for assistive technology.
uiSizeTRUiSize? · density defaultOverride the row and content scale supplied by TRUiDensityScope.

TRTreeNavGroup properties

PropType / defaultPurpose
value, label, childrenT, Widget, List<TRTreeNavItem<T>> · requiredIdentify the group and define its trigger and nested nodes.
initiallyExpandedbool · falseAdds the group to the initial expanded set.
keyKey? · nullIdentifies the rendered group row for state restoration and precise interaction.
descriptionWidget? · nullAdds a muted secondary line below the group label.
disabled, leading, trailingbool?, Widget?, Widget? · nullDisable expansion or decorate the row; trailing replaces the chevron.

TRTreeNavLeaf properties

PropType / defaultPurpose
value, labelT, Widget · requiredIdentify and render a selectable destination.
descriptionWidget? · nullAdds a muted secondary line below the destination label.
keyKey? · nullIdentifies the rendered destination row even when labels repeat.
disabled, leading, trailingbool?, Widget?, Widget? · nullBlock selection or add content before and after the label.
showDisclosureIndicatorbool · falseShow a direction-aware indicator after trailing content for an enabled destination.

TRTreeNavController API

PropType / defaultPurpose
value, expandedT?, Set<T>Read the current selection and an unmodifiable expanded set.
select, togglevoid Function(T?), void Function(T)Change selection or invert one group’s expansion.
setExpanded, replaceExpandedmethodsSet one group or replace the complete expanded set.