Flutter - Using ExcludeSemantics & BlockSemantics Examples

This tutorial shows you how to use ExcludeSemantics and BlockSemantics widgets in Flutter.

Flutter allows you to set the semantics of a widget or a subtree by wrapping it as the child of Semantics widget. Some widgets provided by Flutter already have semantics by default. The semantics information provided by the application can be very useful for accessibility services. Therefore, we should give appropriate semantics for the user interface displayed on the screen. However, sometimes we want certain parts of the user interface to not have semantics. In this tutorial, I am going to show you how to do that.

This tutorial assumes you already understand about Semantics widget in Flutter. If you do not, you can read our tutorial about Semantics.

Using ExcludeSemantics

If there are some widgets that are used as decoration only and not meaningful to users, you may want to exclude the widgets from the semantics tree. To do so, you can use ExcludeSemantics widget. The ExcludeSemantics is a widget that drops all the semantics of its descendants.

  const ExcludeSemantics({
    Key? key,
    bool excluding = true,
    Widget? child,
  })

To exclude a subtree from the semantics tree, you can set it as the child of the ExcludeSemantics widget. The constructor also has a named argument excluding which allows you to dynamically include or exclude a subtree from the semantics tree.

  const ExcludeSemantics(
    child: const Text('........'),
  ),

Output:

Flutter - ExcludeSemantics

Using BlockSemantics

In some cases, you may want that the semantics are only set for particular widgets on a subtree. For example, when a popup is being displayed, it means the user can only interact with the popup. The other widgets should not have semantics at that moment. Let's say we want to create a layout like the below screenshot.

Flutter - BlockSemantics - Layout

There is a button that for displaying a popup. The popup itself is created using Card. When the popup is being displayed, the user can only interact with the popup. At that moment, the other widgets behind the popup should not have semantics, including the 'Show popup' button. Actually you can use ExcludeSemantics to wrap the 'Show popup' button and use a state variable and set the value according to the visibility of the popup. However, if there are many widgets, you may need to use ExcludeSemantics on each widget behind the popup. Fortunately, there is a better way to achieve the same condition. Flutter has another widget BlockSemantics. It's a widget that drops the semantics of all widgets that were painted before it in the same semantic container.

  const BlockSemantics({
    Key? key,
    bool blocking = true
    Widget? child
  })

You can use BlockSemantics and pass the popup widget as the child argument. The constructor has a named argument blocking which indicates whether it should drop the semantics of other widgets painted before it. Therefore, you can pass a state variable to make the value true when the popup is being displayed or false otherwise.

  class _SemanticsExampleState extends State<SemanticsExample> {
  
    bool _showCard = false;
    static const TextStyle textStyle = const TextStyle(color: Colors.white);
  
    Widget _buildCard() {
      return Card(
        color: Colors.teal,
        child: SizedBox(
          width: 200,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              const ListTile(
                leading: const FlutterLogo(),
                title: Text('Flutter Tutorial', style: textStyle),
                subtitle: Text('by Woolha', style: textStyle),
              ),
              ButtonTheme(
                child: ButtonBar(
                  children: <Widget>[
                    TextButton(
                      child: const Text('OK', style: textStyle),
                      onPressed: () => setState(() { _showCard = false; }),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      );
    }
  
    @override
    Widget build(BuildContext context) {
      return SizedBox(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            SizedBox(
              width: 400,
              height: 160,
              child: Stack(
                alignment: Alignment.topCenter,
                children: [
                  Positioned(
                    bottom: 0,
                    child: OutlinedButton(
                      child: Text('Show popup'),
                      onPressed: () => setState(() { _showCard = true; }),
                    ),
                  ),
                  BlockSemantics(
                    blocking: _showCard,
                    child: Visibility(
                      visible: _showCard,
                      child: _buildCard(),
                    ),
                  )
                ],
              ),
            ),
          ],
        ),
      );
    }
  }

When the popup is being displayed and the showSemanticsDebugger is set to true, the output is:

Flutter - BlockSemantics - true

As the opposite, if we don't use BlockSemantics (or if the blocking value is false), the semantics of the 'Show popup' button will not be dropped.

Flutter - BlockSemantics - false

Full Code

  import 'package:flutter/material.dart';
  import 'package:flutter/rendering.dart';
  
  void main() => runApp(MyApp());
  
  class MyApp extends StatelessWidget {
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        showSemanticsDebugger: true,
        home:  Scaffold(
          appBar: AppBar(
            title: const Text('Woolha.com Flutter Tutorial'),
            backgroundColor: Colors.teal,
          ),
          body: SemanticsExample(),
        ),
      );
    }
  }
  
  class SemanticsExample extends StatefulWidget {
  
    @override
    State<StatefulWidget> createState() {
      return _SemanticsExampleState ();
    }
  }
  
  class _SemanticsExampleState extends State<SemanticsExample> {
  
    bool _showCard = false;
    static const TextStyle textStyle = const TextStyle(color: Colors.white);
  
    Widget _buildCard() {
      return Card(
        color: Colors.teal,
        child: SizedBox(
          width: 200,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              const ListTile(
                leading: const FlutterLogo(),
                title: Text('Flutter Tutorial', style: textStyle),
                subtitle: Text('by Woolha', style: textStyle),
              ),
              ButtonTheme(
                child: ButtonBar(
                  children: <Widget>[
                    TextButton(
                      child: const Text('OK', style: textStyle),
                      onPressed: () => setState(() { _showCard = false; }),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      );
    }
  
    @override
    Widget build(BuildContext context) {
      return SizedBox(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const ExcludeSemantics(
              child: const Text('........'),
            ),
            SizedBox(
              width: 400,
              height: 160,
              child: Stack(
                alignment: Alignment.topCenter,
                children: [
                  Positioned(
                    bottom: 0,
                    child: OutlinedButton(
                      child: Text('Show Card'),
                      onPressed: () => setState(() { _showCard = true; }),
                    ),
                  ),
                  BlockSemantics(
                    blocking: _showCard,
                    child: Visibility(
                      visible: _showCard,
                      child: _buildCard(),
                    ),
                  )
                ],
              ),
            ),
          ],
        ),
      );
    }
  }

Output:

Flutter - ExcludeSemantics & BlockSemantics - Full Code

Summary

That's how to not include the semantics of widget subtrees in Flutter. You can use either ExcludeSemantics or BlockSemantics depending on the case.

You can also read about: