custom_cursor_with_icon 1.0.0
custom_cursor_with_icon: ^1.0.0 copied to clipboard
A Flutter TextField widget with an animated cursor that displays a customizable icon below the caret. Fully configurable cursor appearance, blinking behavior, and icon placement.
custom_cursor_with_icon #
A Flutter TextField widget with an animated cursor that displays a customizable icon below the caret. Replace Flutter's default cursor with a fully configurable cursor line and any widget as the cursor icon -- perfect for branded text fields, creative UIs, or playful input experiences.
Demo #
https://github.com/user-attachments/assets/8cf6ea62-67de-4bef-bffc-514674e64fd1
https://github.com/lakshya1goel/custom_cursor_with_icon/raw/main/assets/preview_video.mp4
Features #
- Custom cursor icon -- use any widget (icons, images, Lottie animations, custom shapes) below the caret
- Animated blinking -- configurable blink duration and behavior (always, only when focused, or static)
- Cursor styling -- color, width, height ratio, and glow/shadow effects
- Overflow handling -- smart fade effect at the left edge when text scrolls
- Hint text -- with custom styling and horizontal offset
- Focus control --
showCursorWhenUnfocusedto keep the cursor visible without focus - Full TextField API -- input formatters, keyboard types, obscure text, max length, read-only, and more
- Zero config -- works out of the box with sensible defaults, no required parameters
Installation #
Add to your pubspec.yaml:
dependencies:
custom_cursor_with_icon: ^1.0.0
Then run:
flutter pub get
Quick Start #
import 'package:custom_cursor_with_icon/custom_cursor_with_icon.dart';
Minimal -- zero configuration #
const CustomCursorTextField()
With hint and custom icon #
CustomCursorTextField(
hint: 'Type something...',
icon: Icon(Icons.edit, size: 12, color: Colors.blue),
cursorColor: Colors.blue,
onChanged: (value) => print(value),
)
Examples #
Glow cursor with shadow #
CustomCursorTextField(
cursorColor: Colors.blue,
cursorWidth: 2.0,
cursorBoxShadow: [
BoxShadow(
color: Colors.blue.withValues(alpha: 0.6),
blurRadius: 8,
spreadRadius: 2,
),
],
icon: Icon(Icons.auto_awesome, size: 12, color: Colors.blue),
)
Always-visible cursor (even when unfocused) #
CustomCursorTextField(
showCursorWhenUnfocused: true,
cursorColor: Colors.green,
icon: Icon(Icons.fiber_manual_record, size: 8, color: Colors.green),
)
Blink only when focused #
CustomCursorTextField(
shouldBlinkAlways: false,
unfocusOnTapOutside: true,
)
With input formatting #
CustomCursorTextField(
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
suffixIcon: Icon(Icons.pin),
)
Any widget as cursor icon #
CustomCursorTextField(
iconSize: 18,
icon: ClipRRect(
borderRadius: BorderRadius.circular(9),
child: Image.network('https://i.pravatar.cc/100', width: 18, height: 18),
),
)
Full InputDecoration override #
CustomCursorTextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Email',
prefixIcon: Icon(Icons.email),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
)
API Reference #
Cursor Appearance #
| Parameter | Type | Default | Description |
|---|---|---|---|
cursorColor |
Color? |
Theme.colorScheme.primary |
Color of the cursor line |
cursorWidth |
double |
1.0 |
Width of the cursor line |
cursorHeightRatio |
double |
0.75 |
Cursor height as a fraction of text height |
cursorBoxShadow |
List<BoxShadow>? |
none | Shadow/glow effect on the cursor line |
Icon #
| Parameter | Type | Default | Description |
|---|---|---|---|
icon |
Widget? |
dropdown arrow | Widget displayed below the cursor |
iconSize |
double |
12.0 |
Width and height constraint for the icon |
iconGap |
double |
4.0 |
Gap between cursor line bottom and icon top |
iconTopOffset |
double |
0.0 |
Additional vertical offset for the icon |
iconLeftOffset |
double |
0.0 |
Additional horizontal offset for the icon |
Blink Behavior #
| Parameter | Type | Default | Description |
|---|---|---|---|
blinkDuration |
Duration |
500ms |
Half-cycle duration of the blink animation |
shouldBlinkAlways |
bool |
true |
Whether to blink continuously, even when unfocused |
showCursorWhenUnfocused |
bool |
false |
Show cursor and icon when the field is not focused |
Text & Input #
| Parameter | Type | Default | Description |
|---|---|---|---|
controller |
TextEditingController? |
auto-created | Controls the text being edited |
style |
TextStyle? |
theme default | Text style for the input |
hint |
String? |
none | Hint text displayed when field is empty |
hintStyle |
TextStyle? |
grey version of style | Style for hint text |
hintLeftOffset |
double |
0.0 |
Extra horizontal offset for hint text |
textAlign |
TextAlign |
start |
Horizontal text alignment |
textCapitalization |
TextCapitalization |
none |
Text capitalization behavior |
inputFormatters |
List<TextInputFormatter>? |
none | Input validation and formatting |
keyboardType |
TextInputType? |
none | Keyboard type |
textInputAction |
TextInputAction? |
none | Keyboard action button |
maxLines |
int? |
1 |
Maximum number of lines |
minLines |
int? |
none | Minimum number of lines |
maxLength |
int? |
none | Maximum character count |
obscureText |
bool |
false |
Whether to hide text (for passwords) |
obscuringCharacter |
String |
'*' |
Character used when text is obscured |
readOnly |
bool |
false |
Whether the field is read-only |
enabled |
bool? |
true |
Whether the field is enabled |
Layout & Decoration #
| Parameter | Type | Default | Description |
|---|---|---|---|
contentPadding |
EdgeInsetsGeometry? |
EdgeInsets.all(12) |
Padding inside the field |
suffixIcon |
Widget? |
none | Widget at the end of the field |
decoration |
InputDecoration? |
auto-built | Full decoration override |
overflowFadeWidth |
double? |
horizontal padding | Width of the overflow fade effect |
overflowFadeGradient |
LinearGradient? |
transparent → black | Custom overflow gradient |
Focus & Interaction #
| Parameter | Type | Default | Description |
|---|---|---|---|
focusNode |
FocusNode? |
auto-created | Focus control |
autofocus |
bool |
false |
Auto-focus on mount |
unfocusOnTapOutside |
bool |
false |
Unfocus when tapping outside |
unfocusOnKeyboardDismiss |
bool |
false |
Unfocus when keyboard is dismissed |
enablePaste |
bool |
false |
Show paste option in selection toolbar |
selectionControls |
TextSelectionControls? |
none | Custom text selection controls |
Callbacks #
| Parameter | Type | Default | Description |
|---|---|---|---|
onChanged |
ValueChanged<String>? |
none | Called when text changes |
onSubmitted |
ValueChanged<String>? |
none | Called when user submits |
onEditingComplete |
VoidCallback? |
none | Called when editing is complete |
onTap |
VoidCallback? |
none | Called when field is tapped |
Migration from 0.1.0 #
The cursor is now hidden when unfocused by default. If you relied on the cursor being visible at all times, add:
CustomCursorTextField(
showCursorWhenUnfocused: true,
)
Running the Example #
The example app includes 6 demos: @ symbol icon, network image, Lottie animation, borderless input, glassmorphism with suffix, and always-visible cursor.
cd example
flutter create . # generate platform folders if needed
flutter run
Contributing #
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
License #
MIT License. See LICENSE for details.