86

How can the cursor appearance be changed within Flutter? I know that with the Listener() Widget we can listen for Mouse-Events, but I haven't found any information regarding hovering events for flutter web.

Has someone found a soulution yet?

Vega
28.8k28 gold badges121 silver badges151 bronze badges
asked May 19, 2019 at 20:44
1
  • SO is Q&A site, we don not include answers in question posts. If you wish, then post an answer Commented Feb 21, 2024 at 13:00

9 Answers 9

171

I had difficulties finding documentation on the now built-in support. Here is what helped me: https://github.com/flutter/flutter/issues/58260

And this did the trick for me, without changing index.html etc.

MouseRegion(
 cursor: SystemMouseCursors.click,
 child: GestureDetector(
 child: Icon(
 Icons.add_comment,
 size: 20,
 ),
 onTap: () {},
 ),
 ),

Also see the official documentation: https://api.flutter.dev/flutter/rendering/MouseCursor-class.html

Widget build(BuildContext context) {
 return Center(
 child: MouseRegion(
 cursor: SystemMouseCursors.text,
 child: Container(
 width: 200,
 height: 100,
 decoration: BoxDecoration(
 color: Colors.blue,
 border: Border.all(color: Colors.yellow),
 ),
 ),
 ),
 );
}

And here https://api.flutter.dev/flutter/material/MaterialStateMouseCursor-class.html yet another wonderful example from the official docs that "...defines a mouse cursor that resolves to SystemMouseCursors.forbidden when its widget is disabled."

answered Jun 18, 2020 at 6:28
Sign up to request clarification or add additional context in comments.

5 Comments

Things are changing fast with Flutter. A few weeks ago Khari Lane's answer worked but I couldn't get it to now. This works great and does not require a bunch of custom code or changing index.html.
In 2021, looks like this is done automatically with a 1.22 updates to buttons
This import is also needed import 'package:flutter/rendering.dart';
how about for DropdownButton its not work for this .
in case require to use the regular arrow pointer, use: SystemMouseCursors.basic
20

Starting with dev channel build version 1.19.0–3.0.pre there is built-in support for the pointer cursor. The same method as bellow is used with the difference that is applied to the Flutter app container element flt-glass-pane. Using the bellow method will just duplicate the behavior.

In order to override the pointer cursor, you can use the bellow method but applied on the flt-glass-pane element.

A workaround for this is the following:

  1. You have to set an id (for example app-container on the entire body of the app's index.html template).

This is how your index.html will look like:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>My awesome app</title>
</head>
<body id="app-container">
 <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
  1. Next, you have to create a wrapper dart class. I called it hand_cursor.dart:
import 'package:flutter_web/gestures.dart';
import 'package:flutter_web/widgets.dart';
import 'package:universal_html/html.dart' as html;
// see https://pub.dev/packages/universal_html
class HandCursor extends MouseRegion {
 // get a reference to the body element that we previously altered 
 static final appContainer = html.window.document.getElementById('app-container');
 HandCursor({Widget child}) : super(
 onHover: (PointerHoverEvent evt) {
 appContainer.style.cursor='pointer';
 // you can use any of these: 
 // 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
 // more options/details here: http://www.javascripter.net/faq/stylesc.htm
 },
 onExit: (PointerExitEvent evt) {
 // set cursor's style 'default' to return it to the original state
 appContainer.style.cursor='default';
 },
 child: child
 );
}
  1. After that, wherever you want to have the hand cursor shown, you have to wrap your element in this HandCursor wrapper. See the class awesome_button.dart bellow:
import 'package:awesome_app/widgets/containers/hand_cursor.dart';
import 'package:flutter_web/material.dart';
import 'package:flutter_web/widgets.dart';
class AwesomeButton extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Stack(
 children: <Widget>[
 HandCursor(
 child: IconButton(
 onPressed: () {
 // do some magic
 },
 icon: Icon(Icons.star)
 ),
 )
 ],
 );
 }
}

A short explanation can be found here.

A more versatile update, that works on the new web projects created with the master channel of Flutter, can be found here.

I hope it helps.

answered Sep 6, 2019 at 21:25

1 Comment

Thank you for this answe, it seems legit. I will try it out when I have time to and will come back here.
16

You can use an InkWell that has an onHover event

InkWell(
 onTap: () {},
 onHover: (value) {
 setState(() {
 isHovered = value;
 });
 },
 child: Container(
 width: 50,
 height: 72,
 color: Colors.black 
 )
);

Make sure to have something onTap, even an empty function, else it is considered to be disabled, and the hover won't work

answered Nov 30, 2020 at 23:49

Comments

9

The previous method is deprecated. Here is the updated code

import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;
class HandCursor extends MouseRegion {
 static final appContainer = html.window.document.getElementById('app-container');
 HandCursor({Widget child})
 : super(
 onHover: (PointerHoverEvent evt) {
 appContainer.style.cursor = 'pointer';
 },
 onExit: (PointerExitEvent evt) {
 appContainer.style.cursor = 'default';
 },
 child: child,
 );
}

And in your pubspec.yaml file, add universal_html as a package as a dependency. The version may change.

dependencies:
 flutter:
 sdk: flutter
 universal_html: ^1.1.4

You still want to have an id of app-container attached to the body of your html. Here is my html file.

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Your App Title</title>
</head>
<body id="app-container">
 <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

You want to put the code for the HandCursor widget in its own file. You can call it hand_cursor.dart. And to use it on the widget you want the hand to show up on, import it into the file you're working on and wrap the widget you want in the HandCursor widget.

answered Nov 14, 2019 at 1:15

Comments

8

The most easy way what I know is to use Inkwell.mouseCursor

 InkWell(
 onTap: (){},
 mouseCursor: WidgetStateMouseCursor.clickable,
 ...
 child: YourWidget()
)
Mahesh Jamdade
20.8k11 gold badges132 silver badges150 bronze badges
answered Jan 14, 2022 at 12:36

Comments

7

From Flutter beta version 1.19.0-4.1.pre, add id to body and set cursor of that doesn't work. Because flt-glass-pane is replacing the cursor. So the solution is that set cursor directly to flt-glass-pane.

Below is the update that is working.

class HandCursor extends MouseRegion {
 static final appContainer = html.window.document.querySelectorAll('flt-glass-pane')[0];
 HandCursor({Widget child}) : super(
 onHover: (PointerHoverEvent evt) {
 appContainer.style.cursor='pointer';
 },
 onExit: (PointerExitEvent evt) {
 appContainer.style.cursor='default';
 },
 child: child
 ); 
}
answered Jun 19, 2020 at 4:14

1 Comment

Been looking for this for quite a while, thanks for that!!
5
final appContainer 
 = html.document.getElementsByTagName('body')[0] as html.Element;
 GestureDetector(
 child: MouseRegion(
 child: Text(
 'https://github.com/yumi0629',
 style: textStyle,
 ),
 onHover: (_) => appContainer.style.cursor = 'pointer',
 onExit: (_) => appContainer.style.cursor = 'default',
 ),
 onTap: () {
 print('open');
 js.context.callMethod(
 'open', ['https://github.com/yumi0629']);
 },
 )
answered Mar 25, 2020 at 1:59

Comments

4

I believe that mouse events won't work on the web, Listener Widget was demoed on Google I/O 2019 and worked with mouse, but that was as a ChromeOS app and not a web app.

According to Flutter web on GitHub:

At this time, desktop UI interactions are not fully complete, so a UI built with flutter_web may feel like a mobile app, even when running on a desktop browser.

answered Jun 5, 2019 at 16:24

Comments

2

Adapted answer by Constantin Stan

For those who want to have the click effect similar to InkWell widget and with border radius option:

Add to your pubspec.yaml file

dependencies:
 universal_html: ^1.1.4

Then add to the index.html file the following the tag <body id="app-container"> as below:

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Your App Title</title>
</head>
<body id="app-container">
 <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

Finally create the following widget and use encapsulated all the necessary widgets:

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;
class InkWellMouseRegion extends InkWell {
 InkWellMouseRegion({
 Key key,
 @required Widget child,
 @required GestureTapCallback onTap,
 double borderRadius = 0,
 }) : super(
 key: key,
 child: !kIsWeb ? child : HoverAware(child: child),
 onTap: onTap,
 borderRadius: BorderRadius.circular(borderRadius),
 );
}
class HoverAware extends MouseRegion {
 // get a reference to the body element that we previously altered 
 static final appContainer = html.window.document.getElementById('app-container');
 HoverAware({Widget child}) : super(
 onHover: (PointerHoverEvent evt) {
 appContainer.style.cursor='pointer';
 // you can use any of these: 
 // 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
 // more options/details here: http://www.javascripter.net/faq/stylesc.htm
 },
 onExit: (PointerExitEvent evt) {
 // set cursor's style 'default' to return it to the original state
 appContainer.style.cursor='default';
 },
 child: child
 );
}
answered Dec 18, 2019 at 19:26

1 Comment

If you app is web only , you don't need to depend on "universal_html" package , just 'import 'dart:html' as html' will work.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.