flutter_app_tour
A lightweight, customizable guided-tour overlay for Flutter onboarding flows and feature discovery.
flutter_app_tour highlights real widgets in your app, positions a tooltip around each target, and provides simple step navigation without adding a state-management framework.
Features
- Multi-step widget tours with previous, next, skip, and completion controls.
- Automatic scrolling and tooltip placement.
- Custom spotlight shapes, animations, themes, and tooltips.
- Optional persistence through
TourStorage.
Requirements
- Flutter
3.44.0or later - Dart
3.12.2or later
Installation
Add the latest version shown on pub.dev to your app's pubspec.yaml:
dependencies:
flutter_app_tour: ^0.0.1
Then run:
flutter pub get
Quick start
Create a GlobalKey for each widget you want to highlight. Register the same key and TourId in both TourStep and TourTarget.
import 'package:flutter/material.dart';
import 'package:flutter_app_tour/flutter_app_tour.dart';
class TourHomePage extends StatefulWidget {
const TourHomePage({super.key});
@override
State<TourHomePage> createState() => _TourHomePageState();
}
class _TourHomePageState extends State<TourHomePage> {
final searchKey = GlobalKey();
final profileKey = GlobalKey();
late final controller = TourController(
steps: [
TourStep(
id: TourId('search'),
targetKey: searchKey,
title: 'Search',
description: 'Find projects, notes, and teammates quickly.',
),
TourStep(
id: TourId('profile'),
targetKey: profileKey,
title: 'Profile',
description: 'Manage your account details and preferences here.',
),
],
);
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TourScope(
controller: controller,
child: Scaffold(
appBar: AppBar(
title: const Text('My App'),
actions: [
TourTarget(
id: TourId('search'),
controller: controller,
targetKey: searchKey,
child: IconButton(
tooltip: 'Search',
onPressed: () {},
icon: const Icon(Icons.search),
),
),
TourTarget(
id: TourId('profile'),
controller: controller,
targetKey: profileKey,
child: IconButton(
tooltip: 'Profile',
onPressed: () {},
icon: const Icon(Icons.account_circle_outlined),
),
),
],
),
body: const Center(child: Text('Welcome!')),
floatingActionButton: FloatingActionButton.extended(
onPressed: controller.start,
label: const Text('Start tour'),
),
),
);
}
}
TourScope must wrap the screen subtree containing the target widgets. A target must be mounted before its step can be shown.
Customize steps
Customize tooltip placement, animation, spotlight shape, and scrolling per step:
TourStep(
id: TourId('insights'),
targetKey: insightsKey,
title: 'Weekly insights',
description: 'Review your activity and progress here.',
tooltipPosition: TooltipPosition.auto,
animation: TourAnimation.pulse,
spotlightShape: SpotlightShape.roundedRectangle,
spotlightPadding: 10,
spotlightRadius: 16,
scrollToTarget: true,
)
Use TooltipPosition.top, bottom, left, right, or auto. Available animations are none, pulse, glow, ripple, bounce, and floating.
Custom theme
Set defaults for the complete tour with TourTheme. Individual TourStep values override the relevant spotlight and positioning defaults.
final controller = TourController(
theme: const TourTheme(
overlayColor: Color(0xff102a43),
overlayOpacity: 0.72,
spotlightPadding: 10,
spotlightRadius: 16,
spotlightShape: SpotlightShape.roundedRectangle,
progressIndicatorType: TourProgressIndicatorType.fraction,
showPreviousButton: true,
showSkipButton: true,
),
steps: steps,
);
Supported spotlight shapes are rectangle, roundedRectangle, circle, and oval. Individual TourStep values override the relevant theme defaults.
Lifecycle callbacks and status
The controller exposes callbacks for analytics or application behavior without requiring an analytics dependency:
final controller = TourController(
steps: steps,
onStarted: () => debugPrint('Tour started'),
onStepChanged: (step) => debugPrint('Showing ${step.id}'),
onCompleted: () => debugPrint('Tour completed'),
onSkipped: () => debugPrint('Tour skipped'),
onDismissed: () => debugPrint('Tour dismissed'),
);
Use controller.status when surrounding UI needs to react to idle, running, completed, or skipped.
Persistence
Persistence is optional. The controller does not require storage, and the package includes a SharedPreferencesTourStorage adapter:
const storage = SharedPreferencesTourStorage();
final controller = TourController(
steps: steps,
storage: storage,
onCompleted: () => storage.markSeen('home-tour-v2'),
onSkipped: () => storage.markSeen('home-tour-v2'),
);
To use another persistence system, implement TourStorage. Use a new ID, such as home-tour-v2, when an updated tour should be shown again.
Async steps
Use onBeforeShow when a target must be prepared before its step is shown.
TourStep(
id: TourId('products'),
targetKey: productsKey,
title: 'Products',
description: 'Browse your product catalog here.',
onBeforeShow: () async {
await loadProducts();
},
)
Custom tooltip
Replace the default tooltip with TourScope.tooltipBuilder:
TourScope(
controller: controller,
tooltipBuilder: (context, step, controller, targetRect, screenSize, theme) {
return Material(
color: theme.tooltipBackgroundColor ?? Colors.white,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(step.title),
),
);
},
child: page,
)
The builder receives the active step, controller, target rectangle, screen size, and resolved theme.
Example project
The example/ application demonstrates a workspace-style screen with:
- Search, drawer, profile, insights, and create targets
- A scrollable multi-step tour
- Automatic tooltip positioning
- Spotlight shapes and animations
- Skip and completion persistence using the versioned ID
home-tour-v2
Run it with:
cd example
flutter pub get
flutter run
Limitations
- Targets must be mounted in the widget tree before their steps can be displayed.
- For targets created only when a drawer, dialog, or route opens, use
onBeforeShowto show that UI first. - Use
tooltipBuilderwhen the default tooltip does not fit your design.
License
This package is available under the MIT license. See LICENSE for details.
Libraries
- flutter_app_tour
- Public API for the flutter_app_tour package.