NakedTooltip
Hover/focus triggered tooltip overlay with positioning and lifecycle callbacks
Headless tooltip component. Handles hover/focus triggers, positioning, timers, and dismissal. Use builder pattern for custom styling.
When to use this
- Help text: Explain UI elements or provide additional context
- Icon explanations: Clarify what icon buttons do
- Form field hints: Show validation rules or input examples
- Feature descriptions: Brief explanations of complex features
Working example: example/lib/api/naked_tooltip.0.dart
.
Basic implementation
import 'package:flutter/material.dart';
import 'package:naked_ui/naked_ui.dart';
class TooltipExample extends StatefulWidget {
const TooltipExample({super.key});
@override
State<TooltipExample> createState() => _TooltipExampleState();
}
class _TooltipExampleState extends State<TooltipExample>
with SingleTickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return NakedTooltip(
positioning: const OverlayPositionConfig(
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.bottomCenter,
),
waitDuration: const Duration(milliseconds: 400),
showDuration: const Duration(seconds: 2),
onOpen: () => _controller.forward(),
onClose: () => _controller.reverse(),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.grey.shade900,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.copy, color: Colors.white, size: 18),
),
overlayBuilder: (context, info) {
return FadeTransition(
opacity: _controller,
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: const Text('Copy to clipboard'),
),
),
);
},
semanticsLabel: 'Copy button tooltip',
);
}
}
Constructor
const NakedTooltip({
Key? key,
required this.child,
required this.overlayBuilder,
this.showDuration = const Duration(seconds: 2),
this.waitDuration = const Duration(seconds: 1),
this.positioning = const OverlayPositionConfig(
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.bottomCenter,
),
this.onOpen,
this.onClose,
this.onOpenRequested,
this.onCloseRequested,
this.semanticsLabel,
})
Key Parameters
child
→ trigger widget that displays the tooltip on hover/focusoverlayBuilder
→(BuildContext, RawMenuAnchorOverlayInfo)
that returns the tooltip body each time it showsshowDuration
→ how long the tooltip stays visible before hiding automaticallywaitDuration
→ delay before showing once hover/focus occurspositioning
→OverlayPositionConfig
controlling anchor & offsetonOpen
/onClose
→ lifecycle hooks useful for animationsonOpenRequested
/onCloseRequested
→ intercept show/hide requests (e.g. async delays)semanticsLabel
→ text announced by assistive technologies on hover/focus
Behaviour Notes
- Tooltips open on pointer hover and keyboard focus
- When
waitDuration
elapses, the overlay opens viaRawMenuAnchor
; timers reset on exit - The overlay hides after
showDuration
; supplyonClose
for exit animations - The trigger remains focusable; use
semanticsLabel
for descriptive text when the trigger has no visible label
Positioning Tips
Use OverlayPositionConfig.offset
to nudge the tooltip position:
const OverlayPositionConfig(
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.bottomCenter,
offset: Offset(0, -8),
);
The overlay builder receives RawMenuAnchorOverlayInfo
(info
in the sample) with anchorRect
, overlaySize
, and position
should you need pointer coordinates for arrow placement.