Flutter Daily: Understanding Keys - When and Why to Use Them

Understanding Keys - When and Why to Use Them

What You’ll Learn

Keys are Flutter’s way of preserving state when widgets move around in the widget tree. Most of the time you don’t need them, but when you’re reordering lists or swapping widgets, Keys become essential for maintaining correct state and avoiding UI bugs.

The Problem Keys Solve

Imagine you have a list of stateful widgets (like checkboxes or text fields). When you reorder them, Flutter might reuse the wrong state for the wrong widget because it matches widgets by type and position, not by identity. Keys tell Flutter “this specific widget is the same one, even if it moved.”

Example: List Reordering Without Keys (Broken)

class ColoredBoxList extends StatefulWidget {
  @override
  _ColoredBoxListState createState() => _ColoredBoxListState();
}

class _ColoredBoxListState extends State<ColoredBoxList> {
  List<Widget> boxes = [
    ColorBox(color: Colors.red),
    ColorBox(color: Colors.blue),
    ColorBox(color: Colors.green),
  ];

  void reorderBoxes() {
    setState(() {
      final first = boxes.removeAt(0);
      boxes.add(first);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ...boxes,
        ElevatedButton(
          onPressed: reorderBoxes,
          child: Text('Reorder'),
        ),
      ],
    );
  }
}

class ColorBox extends StatefulWidget {
  final Color color;
  const ColorBox({required this.color});

  @override
  _ColorBoxState createState() => _ColorBoxState();
}

class _ColorBoxState extends State<ColorBox> {
  bool selected = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => setState(() => selected = !selected),
      child: Container(
        width: 100,
        height: 100,
        color: selected ? widget.color.withOpacity(0.5) : widget.color,
      ),
    );
  }
}

Problem: When you tap a box to select it, then reorder, the selection state stays in the wrong box because Flutter reuses the state based on position!

Example: Fixed with Keys

class _ColoredBoxListState extends State<ColoredBoxList> {
  List<Widget> boxes = [
    ColorBox(key: ValueKey('red'), color: Colors.red),
    ColorBox(key: ValueKey('blue'), color: Colors.blue),
    ColorBox(key: ValueKey('green'), color: Colors.green),
  ];

  void reorderBoxes() {
    setState(() {
      final first = boxes.removeAt(0);
      boxes.add(first);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ...boxes,
        ElevatedButton(
          onPressed: reorderBoxes,
          child: Text('Reorder'),
        ),
      ],
    );
  }
}

Fixed! Now each ColorBox has a unique ValueKey, so Flutter knows which widget is which even after reordering, and the selected state follows the correct box.

Types of Keys

Try It Yourself

Create a simple todo list where each item has a checkbox. Add the ability to reorder items. First implement it WITHOUT keys and tap some checkboxes, then reorder—you’ll see the checked state doesn’t follow the items. Then add ValueKey using the todo item’s ID or text, and watch the state correctly follow items when reordered.

Tip of the Day

When do you need Keys? Only when you’re:

  1. Reordering a list of stateful widgets
  2. Adding/removing stateful widgets in a list
  3. Swapping widgets at the same level in the tree

For stateless widgets or widgets that never reorder, you don’t need Keys. Use them sparingly—they’re tools for specific situations, not something to add everywhere “just in case.”