nextgenSOFTWARE
SOFTWARE NEXT GENERATION

NgDrawer — Navigation drawer

Live component previewTry the controls · demonstration data
Open preview ↗

Manual · Getting started · Code examples · Models

When to use it

Let users switch between application sections while keeping workspace content and navigation state in the parent. Choose a modal overlay or a panel beside the content.

Appearance and live example

Try the Blazor example · Flutter example code

The live Blazor preview is embedded above. Use Reset to restore its initial state. Flutter implementation code is provided below; run the Flutter gallery from the installed developer workspace. Dialogs and drawers start closed; use their Open button. Tooltips appear on hover or keyboard focus.

Behavior and practical rules

State and selection

Expanded/expanded and SelectedId/selectedId belong to the parent. Store callback values and pass them back. An expanded Overlay requires ExpandedChanged/onExpandedChanged so it can be dismissed. CloseOnSelect/closeOnSelect defaults to true: an enabled selection requests the selected ID, then requests collapse in Overlay mode. False keeps the drawer open. Push mode stays expanded after selection. A missing selection callback disables destination buttons. Disabled/disabled blocks the toggle and destination selection but leaves an already-open drawer dismissible through Close, Escape and the backdrop.

Layout and direction

Overlay/overlay defaults to true. Position/position accepts start (default) or end, relative to Rtl/rtl (default false): end is right in LTR and left in RTL. Push panels stack above content below 600 px; the position setting applies to wide side-by-side layouts and overlays. Width/width is 200–400 pixels (default 260); overlays clamp to the viewport. The Flutter push panel is 420 pixels tall with a scrolling destination list. Mini mode and swipe gestures are not implemented.

Templates and data

HeaderTemplate/header replaces the title content while keeping the Close control. FooterTemplate/footer adds content below the list. ItemTemplate/itemBuilder and LeadingTemplate/leadingBuilder customize destination text and decorative icons. Item labels remain accessible names. Item and leading templates must be display-only, without nested interactive controls; keep durable state in the parent, not in templates. Header and footer should be compact so the destination list remains usable.

IsVisible/isVisible filters destinations without deleting the selected ID. IsSeparator/isSeparator renders a divider instead of a destination; it never selects. These predicates must be pure. Replace Items/items when data changes. Up to 100 unique NgOption IDs (1–64 ASCII letters/digits/underscore/hyphen) and nonempty labels (up to 120 characters) are supported, including hidden/separator entries. The application owns routing and permissions. An unknown, hidden or separator SelectedId has no visible selected destination. Full template replacement, arbitrary data-model mapping, automatic URL routing and screen-reader certification remain unimplemented.

Blazor example

Razor / Blazor
<NgCheckBox Label="Keep drawer open" @bind-Value="keepOpen"/>
<NgCheckBox Label="Right-to-left" @bind-Value="rtl"/>
<NgDrawer Label="Workspace navigation" Items="items" @bind-SelectedId="selected"
          @bind-Expanded="expanded" Position="end" Rtl="rtl" CloseOnSelect="@(!keepOpen)"
          IsVisible="ShowItem" IsSeparator="IsDivider">
  <HeaderTemplate><strong>Project workspace</strong></HeaderTemplate>
  <FooterTemplate><small>Signed in as Morgan</small></FooterTemplate>
  <LeadingTemplate Context="item"><span>◆</span></LeadingTemplate>
  <ItemTemplate Context="item"><strong>@item.Label</strong></ItemTemplate>
  <ChildContent><p>Current section: @selected</p><NgTextBox Label="Draft note" @bind-Value="note"/></ChildContent>
</NgDrawer>
@code {
  private bool expanded,keepOpen,rtl; private string? selected="overview",note;
  private readonly NgOption[] items=[new("overview","Overview"),new("divider","Workspace sections"),
    new("reports","Reports"),new("hidden","Internal"),new("locked","Unavailable",true)];
  private bool ShowItem(NgOption item)=>item.Value!="hidden";
  private bool IsDivider(NgOption item)=>item.Value=="divider";
}

Flutter example

Dart / Flutter
bool expanded = false, keepOpen = false, rtl = false; String? selected = 'overview';
final note = TextEditingController();
final items = const [NgOption('overview','Overview'),NgOption('divider','Workspace sections'),
  NgOption('reports','Reports'),NgOption('hidden','Internal'),NgOption('locked','Unavailable',disabled:true)];
@override void dispose(){note.dispose();super.dispose();}
Widget build(BuildContext context) => Column(crossAxisAlignment:CrossAxisAlignment.stretch,children:[
  NgCheckBox(label:'Keep drawer open',value:keepOpen,onChanged:(v)=>setState(()=>keepOpen=v)),
  NgCheckBox(label:'Right-to-left',value:rtl,onChanged:(v)=>setState(()=>rtl=v)),
  NgDrawer(label:'Workspace navigation',items:items,selectedId:selected,
    onSelectedIdChanged:(id)=>setState(()=>selected=id),expanded:expanded,
    onExpandedChanged:(v)=>setState(()=>expanded=v),position:'end',rtl:rtl,closeOnSelect:!keepOpen,
    isVisible:(item)=>item.value!='hidden',isSeparator:(item)=>item.value=='divider',
    header:const Text('Project workspace'),footer:const Text('Signed in as Morgan'),
    leadingBuilder:(_,item)=>const Icon(Icons.folder_outlined,size:18),
    itemBuilder:(_,item)=>Text(item.label,style:const TextStyle(fontWeight:FontWeight.bold)),
    child:Column(crossAxisAlignment:CrossAxisAlignment.stretch,children:[
      Text('Current section: $selected'),NgTextBox(label:'Draft note',controller:note)])),
]);

Blazor parameters and events

Names are case-sensitive. ? permits null. EditorRequired parameters are marked required; other values use the initializer or CLR default.

Parameter Type Default / requirement Purpose
Label string "Navigation" Visible label or accessible name.
Items IReadOnlyList<NgOption> required Input collection. Replace it when changing records or configuration.
SelectedId string? not set Current selected item ID; the parent owns this value.
SelectedIdChanged EventCallback<string> not set Selected item ID for the parent to store.
Expanded bool false Whether the drawer is open; controlled by the parent.
ExpandedChanged EventCallback<bool> not set Requested open state; store it in the parent.
Overlay bool true Use a modal overlay instead of a Push panel.
Width int 260 See the behavior rules and model contract above.
Rtl bool false See the behavior rules and model contract above.
Position string "start" See the behavior rules and model contract above.
CloseOnSelect bool true See the behavior rules and model contract above.
Disabled bool false Disable user interaction.
IsVisible Func<NgOption,bool>? not set See the behavior rules and model contract above.
IsSeparator Func<NgOption,bool>? not set See the behavior rules and model contract above.
ItemTemplate RenderFragment<NgOption>? not set See the behavior rules and model contract above.
LeadingTemplate RenderFragment<NgOption>? not set Decorative leading content for an item; no nested interactive elements.
HeaderTemplate RenderFragment? not set See the behavior rules and model contract above.
FooterTemplate RenderFragment? not set See the behavior rules and model contract above.
ChildContent RenderFragment? not set Razor content; for a wizard, a RenderFragment<int> receiving the active index.

Flutter parameters and events

required marks a mandatory argument even if its type is nullable. key is the standard Flutter Key. The exact constructor below specifies defaults.

Argument Type Purpose
label String Visible label or accessible name.
items List<NgOption> Input collection. Replace it when changing records or configuration.
selectedId String? Current selected item ID; the parent owns this value.
onSelectedIdChanged ValueChanged<String>? Selected item ID for the parent to store.
expanded bool Whether the drawer is open; controlled by the parent.
overlay bool Use a modal overlay instead of a Push panel.
rtl bool See the behavior rules and model contract above.
disabled bool Disable user interaction.
closeOnSelect bool See the behavior rules and model contract above.
position String See the behavior rules and model contract above.
isVisible bool Function(NgOption)? See the behavior rules and model contract above.
isSeparator bool Function(NgOption)? See the behavior rules and model contract above.
itemBuilder Widget Function(BuildContext, NgOption)? See the behavior rules and model contract above.
leadingBuilder Widget Function(BuildContext, NgOption)? Decorative leading widget for an item; no nested interactive controls.
header Widget? See the behavior rules and model contract above.
footer Widget? See the behavior rules and model contract above.
onExpandedChanged ValueChanged<bool>? Requested open state; store it with setState or your state manager.
width int See the behavior rules and model contract above.
child Widget See the behavior rules and model contract above.
Dart / Flutter
const NgDrawer({
    super.key,
    this.label = 'Navigation',
    required this.items,
    this.selectedId,
    this.onSelectedIdChanged,
    this.expanded = false,
    this.onExpandedChanged,
    this.overlay = true,
    this.rtl = false,
    this.disabled = false,
    this.closeOnSelect = true,
    this.position = 'start',
    this.isVisible,
    this.isSeparator,
    this.itemBuilder,
    this.leadingBuilder,
    this.header,
    this.footer,
    this.width = 260,
    required this.child,
  });

Integration and troubleshooting

If the UI does not update, confirm that the parent stores callback values and passes them back. Blazor event handlers need interactive rendering; Flutter requires setState or a state manager. Submit form data only after successful validation.

Check accessible labels, empty/invalid states, disabled actions and narrow layouts. Keyboard support is not full screen-reader certification. Current visual verification targets Web in visible Chrome on Linux/iMac; native mobile platforms are a separate phase.

Source and complete examples

API declarations are generated from current source. Curated examples and behavior live in scripts/manual_content.py; regenerate with python3 scripts/generate_manual.py.