HandCursor for Flutter Web

(in 3 simple steps)

Constantin Stan
3 min readSep 6, 2019
Flutter logo and a hand cursor

Flutter released, some months ago, a Flutter for web implementation (currently available as a technical preview).

I'm quite new to the Dart programming language and to the entire Flutter way of doing things, but I started to like it.

In my exploration of its (current) web capabilities, I stumbled upon several issues, and one of the most visually annoying (in the web browser) is the lack of support for cursor customization.

For example, the classic hand cursor that pops up when we hover a button/link is missing. Without it, people are unable to make a difference between what is an actionable item or just a decorative one.

⚠ Starting with dev channel build version 1.19.0–3.0.pre there is built-in support for the pointer cursor. ⚠

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">
<meta charset="UTF-8">
<title>Your awesome app</title>
<script defer src="main.dart.js" type="application/javascript"></script>
<body id="app-container">

2. 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 'dart:html' as html;
class HandCursor extends Listener { static final appContainer = html.window.document.getElementById('app-container'); HandCursor({Widget child}) : super(
onPointerHover: (PointerHoverEvent evt) {
onPointerExit: (PointerExitEvent evt) {
child: child

The code is quite simple: we extend the Listener class and capture a reference to the appContainer (the HTML body element we just set the app-container id on); then we make sure to listen to the hover/exit events and change the cursor's style accordingly (pointer/default) and pass on the child.

As a choice of cursor styles there are plenty: help, wait, move, crosshair, text or, the one we just used, pointer. More choices and details on this can be found here.

3. After that, wherever you want to have the hand cursor shown, you have to wrap your element in this HandCursor wrapper.

See the awesome_button.dart class 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>[
child: IconButton(
onPressed: () {
// let others know
// you can
// do some magic
icon: Icon(Icons.star)

Next possible steps would be to style the cursor only in non mobile web browsers and to customize the Cursor via a parameter (the default one being pointer). That would mean a refactoring of the current class and maybe a new name: CustomCursor

Tha(nk|t’)s all!