smart_search_list 0.8.0
smart_search_list: ^0.8.0 copied to clipboard
Searchable list and grid widget for Flutter. Offline filtering, async loading, pagination, fuzzy search, grouped lists and grids, and multi-select. Zero dependencies.
0.8.0 - 2026-02-14 #
GridView support: search, filter, sort, pagination, grouping, and multi-select in grid layouts.
New Features #
- SmartSearchGrid: Searchable grid widget with three constructors —
SmartSearchGrid()(offline),.async()(server-driven),.controller()(external controller) - SliverSmartSearchGrid: Sliver variant for
CustomScrollViewintegration, with sticky group headers - GridConfiguration: Layout configuration class for grid delegate, padding, physics, and scroll behavior
- Grouped grids: Section headers with
SliverToBoxAdapter(box) orSliverPersistentHeader(sliver, sticky) per group - Shared base:
SmartSearchWidgetBaseandSmartSearchStateMixineliminate duplicated lifecycle code across all 4 widgets (internal, not exported)
Breaking Changes #
onRefreshremoved fromSliverSmartSearchList: Sliver widgets cannot contain aRefreshIndicator. Wrap yourCustomScrollViewwithRefreshIndicatorand callcontroller.refresh()directly insteadonSearchChangedonSliverSmartSearchListis no longer silently ignored: Previously the parameter was accepted but the callback was never called. It now fires post-debounce when the controller's query value changes. If you passed a callback that assumed it would not be invoked, remove it or update it
Improvements #
- Grid examples: 5 new demos (grid, async grid, grouped grid, sliver grid, controller grid) — 19 total
- Search highlighting in grid:
SearchHighlightTextdemonstrated in grid example
Tests #
- 499 tests (up from 312), including grid widget tests, grid controller swap tests, and
addTearDownadoption for test isolation
Backward Compatibility #
- All existing
SmartSearchListandSliverSmartSearchListcode compiles without changes, except for the two breaking changes noted above
0.7.5 - 2026-02-13 #
Fix 3 widget lifecycle bugs and 1 cache crash, add 89 edge case and property-based tests (312 total).
Bug Fixes #
- Scroll controller swap:
SmartSearchList.didUpdateWidgetnow handlesscrollControllerprop changes — moves pagination and keyboard-dismiss listeners to the new controller, disposes internally-created ones, and tracks ownership correctly - Accessibility toggle: Changing
searchSemanticsEnabledmid-lifecycle (without swapping the controller) now correctly adds or removes the announcement listener in bothSmartSearchListandSliverSmartSearchList - Cache crash:
maxCacheSize=0withcacheResults=trueno longer throwsRangeError— the eviction guard now checks_cacheKeys.isNotEmptybefore removing, andmaxCacheSize=0skips cache storage entirely
Internal #
- Debug assertions: Added 49
assert()statements across 6 lib/ files for earlier detection of invalid state in debug mode — no impact in release builds
0.7.4 - 2026-02-13 #
Fix stale notification bug in async mode, improve pub.dev discoverability, and add disposal safety to README examples.
Bug Fixes #
- Stale async notification: Superseded async search requests no longer fire a redundant
notifyListeners()from_performSearch— eliminates one unnecessary widget rebuild per superseded request
Documentation #
- README: Controller example now shows
dispose()in aStatefulWidgetcontext, consistent with the package's disposal safety emphasis
Metadata #
- pub.dev topics: Replaced generic
widgetandpaginationwithfuzzy-searchandaccessibility— both are unique differentiators with low competition for better discoverability
0.7.3 - 2026-02-13 #
Fix cache corruption bug in pagination and sort cache invalidation, plus edge-case test coverage.
Bug Fixes #
- Cache corruption fix:
loadMoreno longer corrupts cached first-page results — cache reads now use a defensive copy to preventaddAllfrom mutating cached entries - Sort cache invalidation:
setSortBynow clears the cache before re-searching, matching the documented behavior and the pattern used bysetFilter,updateCaseSensitive, and other config-change methods - Scroll listener leak:
dispose()now unconditionally removes scroll listeners, preventing a leak when pagination or keyboard config changed betweeninitStateanddispose
Documentation #
- README: Replaced
print()in multi-select example with actionablesetStatepattern - Example app: Removed misleading
caseSensitive/minSearchLengthfromsearchConfigin.controller()mode advanced config example
0.7.2 - 2026-02-12 #
Pre-publish polish: migration guide, SearchHighlightText test coverage, and pub.dev archive optimization.
Documentation #
- Migration guide: Added "Upgrading from v0.6.x" section to README with constructor migration instructions
- GIF exclusion: Added
doc/images/*.gifto.pubignoreto save ~2.3 MB from pub.dev archive (GIFs load from GitHub raw URLs) - Example README: Replaced boilerplate with table listing all 14 demos
0.7.1 - 2026-02-12 #
README rewrite for pub.dev readiness with problem-solution opening, vertical GIF layout, and .controller() example.
Documentation #
- README overhaul: Rewrote for pub.dev -- problem-solution opening paragraph, vertical GIF layout with captions at 320px, simplified installation to
flutter pub add - Controller example: Added
.controller()Quick Start section showing external filter, sort, and setItems usage - Removed badges: Deferred pub.dev badges until after first publish to avoid broken shield images
- Removed Platform Support section: Folded "all platforms" into Features list (pub.dev shows this in sidebar)
- Added Example App section: Prominent link to the 14-demo example app
Bug Fixes #
- Spanish localization typo: Fixed
'Borrar busqueda'to'Borrar búsqueda'in README and accessibility example
0.7.0 - 2026-02-12 #
Named constructors replace nullable params and runtime assertions with compile-time mode enforcement.
Breaking Changes #
- Named constructors:
SmartSearchListandSliverSmartSearchListnow use three constructors:SmartSearchList(items:, searchableFields:, ...)-- offline mode with client-side searchSmartSearchList.async(asyncLoader:, ...)-- async mode where the server handles searchSmartSearchList.controller(controller:, ...)-- fully controller-driven rendering
controllerparameter removed from default and.async()constructors: External controllers are now exclusive to.controller(). This enforces clean mode separation -- each constructor serves exactly one data pattern.cacheResultsandmaxCacheSizeremoved from.controller(): These only apply to internally-created controllers. Configure caching on your controller directly.SmartSearchController.searchableFields: Changed fromrequiredto optional (nullable). Required only for offline search mode.- Removed assertions: The two runtime assertions ("Provide either items OR asyncLoader" and "Provide items, asyncLoader, or a controller") are removed. The compiler now enforces these constraints.
Migration #
- Offline mode (items + searchableFields): No change required. The default constructor signature is identical.
- Offline + external controller (items + controller): Change to
.controller(controller: ...,and callcontroller.setItems(...)yourself. PasssearchableFieldsto the controller constructor. PassdebounceDelay,caseSensitive,minSearchLength,fuzzySearchEnabled, andfuzzyThresholdto the controller constructor instead ofsearchConfig. - Async mode (asyncLoader): Change
SmartSearchList(asyncLoader: ..., searchableFields: ...,toSmartSearchList.async(asyncLoader: ...,and removesearchableFields:. - Async + external controller (asyncLoader + controller): Change to
.controller(controller: ...,and callcontroller.setAsyncLoader(...)yourself. You must also callcontroller.search('')to trigger the initial load — the widget no longer does this automatically for external controllers. - Controller-only mode (controller without items/asyncLoader): Change to
SmartSearchList.controller(controller: ...,and removesearchableFields:. - SmartSearchController: If you were passing
searchableFieldsin async-only usage, you can now omit it.
Documentation #
- README GIFs: Added basic search, fuzzy search, and async pagination demo GIFs
Backward Compatibility #
- The default constructor signature is unchanged for offline mode -- existing offline code compiles without modification.
- This is a breaking change for async, controller, and mixed-mode usage patterns.
0.6.1 - 2026-02-10 #
Dartdoc overhaul, bug fixes, and sliver test coverage.
Bug Fixes #
RichTextreplaced withText.rich:SearchHighlightTextnow usesText.richfor properSelectionAreaparticipation andtextScaleraccessibility support- Scroll listener leak:
SmartSearchListnow always removes scroll listeners before disposal, not just for external controllers - Controller swap safety:
didUpdateWidgetin both widgets now correctly handles external-to-null and null-to-external controller transitions without dangling references - Assertion consistency:
SmartSearchListconstructor assertions now matchSliverSmartSearchList— rejectsitems+asyncLoadersimultaneously even when controller is provided _searchTermsperformance:SliverSmartSearchListnow computes search terms once per build instead of once per item
Documentation #
- Complete dartdoc audit: ~70 missing doc comments added across all public classes, methods, fields, and typedefs
- Effective Dart compliance: fragment summaries converted to complete sentences, third-person verb forms, redundant docs trimmed
- Cross-references converted to bracket refs with imports for clickable pub.dev links
- Filter/sort async vs offline behavior clarified,
ItemBuilder.searchTermslifecycle documented - Aligned
SliverSmartSearchListdocs withSmartSearchListforasyncLoader,groupBy, andaccessibilityConfig
0.6.0 - 2026-02-10 #
Bug fixes and widget tests. Widgets now react to prop changes, cache key correctness fix, and first widget-level test coverage.
Bug Fixes #
didUpdateWidgetsupport:SmartSearchListandSliverSmartSearchListnow react to parent rebuilds — changingitems,asyncLoader,caseSensitive,minSearchLength,fuzzySearchEnabled,fuzzyThreshold, or swapping an external controller after initial build now works correctly- Cache key fix: Calling
setFilterwith the same key but a different predicate no longer returns stale cached results — cache key now includes a filter predicate version counter
0.5.1 - 2026-02-01 #
Improved screen reader announcements for more reliable TalkBack/VoiceOver support.
Improvements #
- Screen reader announcements: Replaced
Semantics(liveRegion: true)withSemanticsService.sendAnnouncement()for more reliable TalkBack and VoiceOver feedback - Removed live region widget: Result count announcements no longer require an extra
SizedBoxin the widget tree
Requirements #
- Minimum Flutter version bumped from 3.13.0 to 3.35.0 (required for
SemanticsService.sendAnnouncement)
0.5.0 - 2026-02-01 #
Accessibility support with TalkBack/VoiceOver and full localization control.
New Features #
- AccessibilityConfiguration: New configuration class for semantic labels and screen reader behavior
searchFieldLabel— custom label for the search text fieldclearButtonLabel— custom tooltip for the clear button (default:'Clear search')searchButtonLabel— custom tooltip for the search button in onSubmit mode (default:'Search')resultsAnnouncementBuilder— customizable announcement text for result count changes (supports localization)searchSemanticsEnabled— opt-out flag to disable all automatic semantics
- Live Region Announcements: Result count changes are announced to screen readers via
Semantics(liveRegion: true)— compatible with Android 16+ (which deprecated imperativeSemanticsService.announce) - Semantic Headers:
DefaultGroupHeadernow includesSemantics(header: true)for proper screen reader navigation - Icon Tooltips: Clear and search
IconButtons inDefaultSearchFieldnow have tooltips for assistive technology
API Changes #
SmartSearchListgainsaccessibilityConfigparameter (default:const AccessibilityConfiguration())SliverSmartSearchListgainsaccessibilityConfigparameterDefaultSearchFieldgainsaccessibilityConfigparameter- New export:
AccessibilityConfiguration
Example Updates #
- New Accessibility example demonstrating localized labels and custom announcement text
0.4.0 - 2026-02-01 #
Fuzzy search with typo-tolerant matching, scored ranking, and built-in highlight widget.
New Features #
- Fuzzy Search: Zero-dependency 3-phase matching algorithm for offline lists
- Phase 1 — Exact substring (score 1.0): standard
indexOffast path - Phase 2 — Ordered subsequence (score 0.01–0.99): handles missing characters ("apl" → "Apple", "bnna" → "Banana") with consecutive-run scoring
- Phase 3 — Bounded Levenshtein (score 0.01–0.59): handles extra/wrong characters and transpositions ("apole" → "Apple", "appel" → "Apple") with
maxEditDistance = 2 - Score-and-sort pipeline: exact matches always rank first, fuzzy matches scored by consecutive runs, density, position, and word boundaries
- Configurable via
SearchConfiguration.fuzzySearchEnabled(default:false) andSearchConfiguration.fuzzyThreshold(default:0.3)
- Phase 1 — Exact substring (score 1.0): standard
- SearchHighlightText Widget: Built-in widget for highlighting matched characters
- Works with both exact substring and fuzzy matching
- Accepts
text+searchTerms, renders highlightedTextSpan - Customizable
matchStyle,highlightColor,maxLines,overflow
- FuzzyMatcher: Public utility class for custom fuzzy matching
FuzzyMatcher.match(query, text)— returns score + match indicesFuzzyMatcher.matchFields(query, fields)— best score across multiple fieldsFuzzyMatchResultwith score andmatchIndicesfor highlighting
API Changes #
SearchConfigurationgainsfuzzySearchEnabledandfuzzyThresholdparametersSmartSearchControllergainsfuzzySearchEnabled,fuzzyThresholdfields andupdateFuzzySearchEnabled(),updateFuzzyThreshold()methods- New export:
FuzzyMatcher,FuzzyMatchResult,SearchHighlightText
Performance Note #
- Fuzzy search (especially Phase 3) is computationally heavier than plain substring search
- For lists > 5,000 items, test performance on target devices or increase
fuzzyThresholdto0.6+to skip expensive edit-distance matches - Subsequence matching (Phase 2) is O(m+n) per item and fast for any list size
- Edit-distance fallback (Phase 3) only runs when Phases 1 and 2 fail — gibberish queries are rejected quickly by length and ratio guards
Example Updates #
- New Fuzzy Search example: toggle fuzzy on/off, adjust threshold, SearchHighlightText demo
0.3.0 - 2026-01-31 #
Progress indicator builder and consistent state builder naming.
New Features #
- Progress Indicator Builder: New
progressIndicatorBuilderparameter onSmartSearchList- Shows an inline widget (e.g., thin progress bar, shimmer) below the search field during async operations
- Unlike
loadingStateBuilder(which replaces the entire list), this renders alongside existing content - Receives
(BuildContext context, bool isLoading)— returnSizedBox.shrink()when not loading
- New
ProgressIndicatorBuildertypedef
Bug Fixes #
- Sliver searchTerms fix:
SliverSmartSearchListnow correctly forwardssearchTermstoitemBuilderin grouped mode — previously, items inside grouped slivers received empty search terms, breaking highlighting
Improvements #
- Cleaned up package description and documentation tone
Breaking Changes #
All state builders renamed for consistency — the *StateBuilder suffix now clearly indicates builders that replace the entire list area:
loadingBuilder→loadingStateBuildererrorBuilder→errorStateBuilderemptyBuilder→emptyStateBuilderemptySearchBuilder→emptySearchStateBuilderLoadingBuilder→LoadingStateBuilderErrorBuilder→ErrorStateBuilderEmptyBuilder→EmptyStateBuilderEmptySearchBuilder→EmptySearchStateBuilder
Migration #
Find-and-replace in your code:
loadingBuilder:→loadingStateBuilder:errorBuilder:→errorStateBuilder:emptyBuilder:→emptyStateBuilder:emptySearchBuilder:→emptySearchStateBuilder:
0.2.0 - 2026-01-31 #
Multi-select, grouped lists, and search trigger modes.
New Features #
- Multi-Select Support: Select/deselect items with checkboxes via
SelectionConfiguration- Controller methods:
toggleSelection(),selectAll(),deselectAll(),selectWhere(),isSelected() - Configurable checkbox position (leading/trailing) and visibility
onSelectionChangedcallback for reacting to selection changes
- Controller methods:
- Grouped Lists: Group items into sections with headers via
groupByfunction- Automatic grouping — provide a
groupBy: (item) => item.categoryfunction DefaultGroupHeaderwith group name and item count- Custom
groupHeaderBuilderfor full control groupComparatorfor ordering groups- Empty groups auto-removed after search/filter
- Sticky headers in
SliverSmartSearchListviaSliverMainAxisGroup
- Automatic grouping — provide a
- Search Trigger Modes: Control when search fires via
SearchTriggerModeenumonEdit(default): debounced search on every keystrokeonSubmit: search only on keyboard submit or search button tapsearchImmediate()method for bypassing debounce programmatically
API Changes #
- New
SearchTriggerModeenum:{ onEdit, onSubmit } - New
SelectionConfigurationclass withenabled,showCheckbox,position - New
CheckboxPositionenum:{ leading, trailing } - New
GroupHeaderBuildertypedef SearchConfigurationgainstriggerModeparameterSmartSearchListgainsselectionConfig,groupBy,groupHeaderBuilder,groupComparator,onSelectionChangedSliverSmartSearchListgains the same plusgroupHeaderExtentfor sticky header sizeSmartSearchControllergains multi-select methods andsearchImmediate()DefaultSearchFieldgainsonSubmittedcallback for submit mode
Breaking Changes #
- Minimum Flutter version bumped from 3.10.0 to 3.13.0 (required for
SliverMainAxisGroup)
Example Updates #
- New Multi-Select example: checkbox list with select all/deselect all
- New Grouped List example: products grouped by category with search
0.1.1 - 2026-01-31 #
Search term highlighting support and below-search widget slot.
New Features #
- Search Term Highlighting:
ItemBuildernow receivessearchTermsparameter for highlighting matched text - Below Search Widget: New
belowSearchWidgetparameter for filters, chips, or custom controls - Pull to Refresh Examples: All example pages now demonstrate pull-to-refresh functionality
API Changes #
ItemBuilder<T>now includes optionalsearchTermsparameter:itemBuilder: (context, item, index, {searchTerms = const []}) { // Use searchTerms for highlighting }- Added
belowSearchWidgetparameter toSmartSearchList
Example Updates #
- All examples updated with search terms highlighting support
- Pull-to-refresh enabled across all example pages
- Improved user experience with better visual feedback
0.1.0 - 2026-01-31 #
Initial release. A high-performance, zero-dependency searchable list package for Flutter.
Features #
- High Performance: Tested with 10,000+ items at 60 FPS
- Memory Safe: Proper disposal patterns, no memory leaks
- Two Empty States: Different messages for "no data" vs "no search results"
- Fully Customizable: Builder patterns for all UI components
- Async Support: Built-in pagination and pull-to-refresh
- Zero Dependencies: Only uses Flutter SDK
Core Components #
SmartSearchList<T>— Main widget with offline and async modesSmartSearchController<T>— Robust controller with disposal safetySearchConfiguration— Flexible search behavior configurationListConfiguration— List appearance and behavior optionsPaginationConfiguration— Pagination settings
Reliability #
- Race condition prevention with request IDs
- Debounced search (300ms default)
- Proper
_isDisposedchecks throughout - Automatic cleanup of timers and listeners
Builder Patterns #
All UI components are customizable:
searchFieldBuilder— Custom search fielditemBuilder— List item rendering (required)loadingStateBuilder— Loading stateerrorStateBuilder— Error state with retryemptyStateBuilder— Empty state (no data)emptySearchStateBuilder— Empty search resultsseparatorBuilder— List separators
Example App #
Complete example app with 7 demonstrations:
- Basic offline list with configuration options
- E-commerce products with filters/sorting
- Async API loading with pagination
- Empty states (no data vs no search results)
- Sliver integration for CustomScrollView
- Advanced configuration with external controller
- Performance test with 10K items