checkboxSelector method
Renders a keyboard-driven checklist prompt and returns the checked labels.
Presents a vertical multi-select checklist with a live summary counter.
Controls:
- ↑ / ↓ navigate
- Space toggles the focused option
- A selects all / clears all
- Enter confirms the selection
- Esc / Ctrl+C cancels (returns
[])
Parameters:
prompt: Heading rendered in the frame title bar.options: String labels displayed next to the checkboxes.initialSelected: Optional set of indices that start checked.maxVisible: Maximum number of rows before scrolling kicks in.
Returns a list containing the labels that were confirmed by the user.
Example:
final choices = terminice.checkboxSelector(
'Options',
options: ['Alpha', 'Beta', 'Gamma'],
initialSelected: {0},
);
Implementation
List<String> checkboxSelector(
String prompt, {
required List<String> options,
Set<int>? initialSelected,
int maxVisible = 12,
}) {
final theme = defaultTheme;
if (options.isEmpty) return <String>[];
return runWithExecutionMode<List<String>>(
rich: () {
// Use SelectableListPrompt for centralized state management
final promptObj = SelectableListPrompt<String>(
title: prompt,
items: options,
theme: theme,
multiSelect: true,
maxVisible: maxVisible,
initialSelection: initialSelected,
);
// Summary line builder (captures promptObj for access to selection state)
String buildSummaryLine() {
final total = options.length;
final count = promptObj.selection.count;
if (count == 0) {
return '${theme.dim}(none selected)${theme.reset}';
}
// render up to 3 selections by label, then "+N"
final indices = promptObj.selection.getSelectedIndices();
final names = <String>[];
for (var i = 0; i < indices.length && i < 3; i++) {
final name = options[indices[i]];
names.add('${theme.accent}$name${theme.reset}');
}
final more = indices.length > 3
? ' ${theme.dim}(+${indices.length - 3})${theme.reset}'
: '';
return '${theme.accent}$count${theme.reset}/${theme.dim}$total${theme.reset} • ${names.join('${theme.dim}, ${theme.reset}')} $more';
}
return promptObj.runCustom(
// Add select-all binding ('A' key)
extraBindings: KeyBindings.letter(
char: 'A',
onPress: () => promptObj.selection.toggleAll(options.length),
hintDescription: 'select all / clear',
),
// Summary line before items
beforeItems: (ctx) {
ctx.gutterLine(buildSummaryLine());
ctx.writeConnector();
},
// Render each item with checkbox
renderItem: (ctx, item, absoluteIdx, isFocused, isChecked) {
final arrow = ctx.lb.arrow(isFocused);
final check = ctx.lb.checkbox(isChecked);
// Construct core line and fit within terminal width with graceful truncation
final cols = TerminalInfo.columns;
var core = '$arrow $check $item';
final reserve = 0; // no trailing widget for now
final gutterLen = ctx.lb.gutter().length;
final maxLabel = (cols - gutterLen - 1 - reserve).clamp(8, cols);
if (core.length > maxLabel) {
core = '${core.substring(0, maxLabel - 3)}...';
}
ctx.highlightedLine(core, highlighted: isFocused);
},
);
},
line: () => FallbackSelection.multi<String>(
title: prompt,
options: options,
defaultIndices: initialSelected,
),
unattended: () => FallbackSelection.initialItems<String>(
options: options,
indices: initialSelected,
multiSelect: true,
),
);
}