Skip to content

SelectionArea widget causes text selection issues on web when wrapping QuillEditor #2688

@armand-sd

Description

@armand-sd

Have you checked for an existing issue?

Flutter Quill Version

11.5.0

Steps to Reproduce

  1. Set up a QuillEditor widget surrounded by regular Text widgets.
  2. Wrap the entire screen with a SelectionArea widget.
  3. Run the app on web.
  4. Select text in the editor (characters, words, paragraphs, etc.)

Expected results

Text selection should be precise from where the drag gesture started up to where the cursor is currently or has ended. Text outside the active QuillEditor widget shouldn’t be selected.

Actual results

Text outside the active QuillEditor is randomly selected while purposefully selecting text in the editor. In some cases, no QuillEditor text is selected at all while external text do.

Additional Context

When running on Flutter web, the presence of a SelectionArea widget causes text selection issues to an active/editing QuillEditor widget. When SelectionArea is removed or not present, text selection behaves as expected. Wrapping the editor with a SelectionContainer.disabled widget doesn't fix the issue either.

Tested on:

  • flutter: 3.32.4 and 3.38.3
  • flutter_quill: 11.4.1 and 11.5.0
  • Fresh Flutter Project and old in-development repository
Screenshots / Video demonstration
with_selectionarea_widget.mov
without_selectionarea_widget.mov
Minimal Reproducible Example
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text Selection Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  QuillController _controller = QuillController.basic();

  @override
  void initState() {
    super.initState();
    final doc = Document.fromJson([
      {
        "insert":
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et orci eu dui feugiat tincidunt id quis mi. Curabitur nec libero elementum, sagittis elit sed, porta ligula. Donec imperdiet tristique augue, a ullamcorper leo hendrerit ac. Sed sed enim in augue cursus aliquet. Ut laoreet eros et tempor suscipit. Nulla ornare, metus non porttitor lacinia, magna mi posuere massa, in gravida diam odio vitae nibh. Curabitur ac lobortis lacus. Pellentesque vitae odio erat. In sagittis tempus ex.\nThe quick brown fox jumps over the lazy dog.",
      },
      {
        "insert": "\n",
        "attributes": {"list": "bullet"},
      },
      {"insert": "The quick brown fox jumps over the lazy dog."},
      {
        "insert": "\n",
        "attributes": {"list": "bullet"},
      },
      {"insert": "The quick brown fox jumps over the lazy dog."},
      {
        "insert": "\n",
        "attributes": {"list": "bullet"},
      },
      {
        "insert":
            "Donec elementum velit sit amet risus mattis, eget pellentesque leo volutpat. Maecenas euismod nisl velit, id elementum sapien elementum sollicitudin. Quisque varius justo odio, quis luctus odio pellentesque pretium. Mauris efficitur blandit lorem, nec posuere leo placerat sed. Sed pharetra purus vitae mi venenatis, sed accumsan diam suscipit. Nulla blandit at nisl iaculis auctor. Vestibulum vulputate neque est, vestibulum tincidunt enim finibus nec.\n\nNullam ex nulla, auctor a viverra et, luctus et lectus. Nunc id porta quam, non ultrices erat. Maecenas in cursus lacus, sed fermentum neque. Cras eu justo arcu. Etiam et augue quis ex rutrum vestibulum nec at purus. Aenean aliquam sollicitudin sodales. Aenean blandit vel ex quis ultricies. Suspendisse nisi libero, pellentesque euismod varius ultrices, laoreet ac sem.\n",
      },
    ]);
    _controller = QuillController(
      document: doc,
      selection: const TextSelection.collapsed(offset: 0),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SelectionArea(
      child: Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,

          title: Text('With SelectionArea Widget'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Expanded(
                child: Row(
                  children: [
                    VerticalDivider(),
                    Text('Regular text in a Text widget.'),
                    VerticalDivider(),
                    Expanded(
                      child: QuillEditor.basic(
                        controller: _controller,
                        config: QuillEditorConfig(
                          padding: EdgeInsetsGeometry.zero,
                        ),
                      ),
                    ),
                    VerticalDivider(),
                    Text('Regular text in a Text widget.'),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions