Search code examples
fluttertextfieldcontextmenu

How to have a custom context menu for TextFields in Flutter?


The flutter (on desktop) shows this custom context menu for the text fields which is absolutely ugly:

Do you know of a way that this can be customized?

UPDATE

I actually found the answer. You have to implement a class based on TextSelectionControls and give it to selectionControls of the TextInputField. Also you can lookup the MaterialTextSelectionControls which has a simple implementation to understand how it is done.


Solution

  • With Flutter 3.7 you can now create custom context menus anywhere in a Flutter app.

    A contextMenuBuilder parameter has been added to many widgets (e.g. TextField, CupertinoTextField, SelectionArea, etc.). You can return any widget you want from contextMenuBuilder, including modifying the default platform-adaptive context menu.

    Example: (source)

    TextField(
      contextMenuBuilder: (context, editableTextState) {
        final TextEditingValue value = editableTextState.textEditingValue;
        final List<ContextMenuButtonItem> buttonItems = editableTextState.contextMenuButtonItems;
        if (isValidEmail(value.selection.textInside(value.text))) {
          buttonItems.insert(
              0,
              ContextMenuButtonItem(
                label: 'Send email',
                onPressed: () {
                  ContextMenuController.removeAny();
                  Navigator.of(context).push(_showDialog(context));
                },
              ));
        }
        return AdaptiveTextSelectionToolbar.buttonItems(
          anchors: editableTextState.contextMenuAnchors,
          buttonItems: buttonItems,
        );
      },
    )
    

    This new feature works outside of text selection too by using ContextMenuController. You could, for example, create an Image widget that shows a Save button when right clicked or long pressed: (source) ContextMenuController

    ContextMenuRegion(
      contextMenuBuilder: (context, offset) {
        return AdaptiveTextSelectionToolbar.buttonItems(
          anchors: TextSelectionToolbarAnchors(
            primaryAnchor: offset,
          ),
          buttonItems: <ContextMenuButtonItem>[
            ContextMenuButtonItem(
              onPressed: () {
                ContextMenuController.removeAny();
                Navigator.of(context).push(_showDialog(context));
              },
              label: 'Save',
            ),
          ],
        );
      },
      child: const SizedBox(
        width: 200.0,
        height: 200.0,
        child: FlutterLogo(),
      ),
    )
    

    You can find more examples of custom context menus in: