hint_kit 1.2.0
hint_kit: ^1.2.0 copied to clipboard
Tooltips, persistent hints and spotlight guided tours from one overlay engine, one placement resolver and one theme. Zero runtime dependencies.
hint_kit #
Flutter toolkit for tooltips, persistent hints, and guided tours using one overlay engine, placement resolver, theme, and controller pattern.
It supports disabled widgets, route-spanning tours, real spotlight passthrough, reusable themes, animations, persistence, localization, analytics, and accessibility β with zero runtime dependencies.
Screenshots #
| Hints, designs and animations | A four-step guided tour |
|---|---|
![]() |
![]() |
Both recorded on a device from example/, captioned as they go. The tour is the one worth watching: the spotlight travels between targets rather than cutting, step 3 expands a panel before it appears, and step 4 waits until you push the route it lives on.
| A hint on a disabled button | The branded preset |
The glass preset |
|---|---|---|
![]() |
![]() |
![]() |
| A tour step, spotlight and all | A retinted, lighter scrim | Dark mode, unconfigured |
|---|---|---|
![]() |
![]() |
![]() |
Every one of these is the example app on a device β nothing is mocked up. Run it yourself: cd example && flutter run.
Features #
- π« Disabled widgets β show hints even when the child is disabled.
- πΊοΈ Guided tours β ordered steps that can continue across routes.
- π¦ Spotlight β real scrim hole with optional hit-test passthrough.
- π¨ 10 presets β
material,minimal,soft,contrast,branded,sharp,card,glass,cupertino,adaptive. - β¨ Animations β
scale,fade,pop,slide,none, or custom. - πΎ Persistence β show-once hints and interrupted-tour resume.
- π Localization β custom labels and progress formatting.
- π Analytics β app-wide hint and tour observer.
- βΏ Accessibility β semantics, focus handling, text scaling, high contrast, reduced motion, and Esc support.
- π¦ Zero dependencies β pure Flutter.
Install #
dependencies:
hint_kit: ^1.1.0
or:
flutter pub add hint_kit
import 'package:hint_kit/hint_kit.dart';
Quick start #
Hint #
Hint(
message: 'You need an active shift to check in',
child: ElevatedButton(
onPressed: null,
child: const Text('Check in'),
),
);
Hint supports tap, longPress, hover, focus, manual, onAppear, and secondaryTap triggers.
Controller #
final controller = HintController();
Hint(
controller: controller,
triggers: const {HintTrigger.manual},
message: 'Saved successfully',
child: saveButton,
);
controller.show();
controller.hide();
controller.toggle();
Guided tours #
Wrap the application with TourScope and mark the steps with HintTarget:
TourScope(
child: MaterialApp(
home: HintTarget(
tour: 'onboarding',
order: 1,
title: 'Start here',
description: 'Tap this button to continue.',
child: const Text('Check in'),
),
),
);
Start the tour with:
Tour.read(context).start('onboarding');
Control a tour with:
tour.next();
tour.previous();
tour.skip();
tour.finish();
tour.cancel();
Tours can wait for targets that are not currently mounted, making route-spanning onboarding possible.
Spotlight & passthrough #
HintTarget(
tour: 'onboarding',
order: 1,
spotlight: SpotlightShape.circle,
passthrough: true,
child: checkInButton,
)
With passthrough: true, interaction inside the spotlight can reach the actual target.
Show once #
Display a hint only once:
Hint(
showOnce: 'payslip-tip',
triggers: const {HintTrigger.onAppear},
message: 'Payslips live here now',
child: payslipTab,
);
For persistent storage, assign your own TourStorage implementation:
TourScope(
storage: myStorage,
child: const MyApp(),
);
HintRegistry.instance.storage = myStorage;
Theming #
Configure a shared theme with HintThemeData:
MaterialApp(
theme: ThemeData(
extensions: const [
HintThemeData(
preset: HintPreset.branded,
maxWidth: 320,
),
],
),
);
Or configure an individual hint:
Hint(
theme: const HintThemeData(
preset: HintPreset.glass,
),
message: 'This is a glass-style hint',
child: button,
);
Themes control colors, borders, radius, elevation, padding, arrow, placement spacing, typography, transitions, blur, scrim, and spotlight settings.
Rich bubbles #
Use contentBuilder for custom interactive content:
Hint(
interactive: true,
triggers: const {HintTrigger.hover, HintTrigger.tap},
contentBuilder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Payslip #4821'),
TextButton(
onPressed: _download,
child: const Text('Download'),
),
],
),
child: chip,
);
Beacon #
For a lightweight alternative to a full tour:
Beacon(
title: 'Duplicate a shift',
message: 'Long-press a shift to copy it.',
pulseCount: 3,
child: const Icon(Icons.calendar_month),
);
API surface #
| Type | Purpose |
|---|---|
Hint |
Tooltip / hint widget |
HintController |
Programmatic hint control |
HintTarget |
Guided-tour step |
TourScope |
Tour configuration and storage |
TourController |
Start and control tours |
HintThemeData |
Shared and per-widget styling |
HintPreset |
Ready-made designs |
HintQueue |
Sequential hints without a tour |
Beacon |
Pulsing hint indicator |
HintObserver |
Analytics / lifecycle events |
TourStorage |
Persistence for tours and show-once hints |
resolvePlacement |
Pure placement resolver |
Requirements #
- Flutter 3.24+
- Dart 3.5+
- Android, iOS, web, macOS, Windows, Linux
Notes #
Hintrequires anOverlayancestor, normally provided byMaterialApp,CupertinoApp, orNavigator.- An ancestor
IgnorePointerorAbsorbPointercan prevent the hint from receiving pointer events. - Lazy off-screen list items cannot be targeted until they are built.
- The default
InMemoryTourStoragedoes not persist between app launches. - A
Beaconwith unlimited pulsing can keep widget tests from settling; usepulseCountor disable auto-start.
Links #
License #
MIT







