Everything is a Widget
The Building Blocks of Every Flutter App
Open interactive version (quiz + challenge)Real-world analogy
What is it?
In Flutter, everything on screen is a widget. A widget is an immutable description of a piece of UI. Widgets are organized in a tree structure where parent widgets contain child widgets. When data changes, Flutter rebuilds the widget tree, compares it to the previous version, and efficiently updates only the parts that changed. This declarative approach means you describe what the UI should look like for a given state, and Flutter figures out how to make it happen.
Real-world relevance
In team_mvp_kit, the entire app is a widget tree. MaterialApp is the root. go_router provides navigation widgets. Each screen is a StatelessWidget or StatefulWidget. BlocBuilder widgets listen to BLoC state and rebuild their subtree when state changes. Every button, text field, list item, and icon is a widget. Understanding the widget tree is essential because it determines how data flows down (via constructors) and events flow up (via callbacks). Clean Architecture in team_mvp_kit keeps business logic out of widgets, making the widget layer a pure UI description.
Key points
- What is a Widget? — A widget is an immutable description of part of the user interface. It is not the actual pixels on screen -- it is a lightweight blueprint that Flutter's engine uses to paint the UI. Widgets are cheap to create and rebuild.
- The Widget Tree — Widgets are nested inside each other forming a tree structure. The root widget is usually MaterialApp or CupertinoApp. Every widget has a parent (except the root) and can have children. Flutter walks this tree to build the UI.
- Composition Over Inheritance — Flutter favors composition: you build complex widgets by combining simple ones. Instead of creating a FancyButton that inherits from Button, you wrap a Button in a Container with styling. This makes widgets flexible and reusable.
- The build Method — Every widget must implement a build method that returns a widget tree describing what this widget looks like. Flutter calls build whenever the widget needs to update. The returned tree can be deeply nested.
- BuildContext — The build method receives a BuildContext that tells the widget where it sits in the tree. Context is used to access theme data, navigate, show dialogs, and find parent widgets. Every widget has its own context.
- Visible vs Invisible Widgets — Some widgets paint pixels (Text, Image, Icon). Others only affect layout or behavior without painting anything themselves (Padding, Center, GestureDetector). Both are equally important -- layout widgets control how visible widgets are positioned.
- Key Concept: Widgets are Immutable — Once created, a widget cannot change. To update the UI, Flutter creates new widget instances and compares them to the old ones. This diffing process is fast because widgets are lightweight descriptions, not heavy UI objects.
- Widget Categories — Flutter widgets fall into categories: structural (Scaffold, AppBar), layout (Row, Column, Stack), presentation (Text, Image), input (TextField, Checkbox), scrolling (ListView, GridView), and styling (Theme, Container).
- The Three Trees — Flutter maintains three parallel trees: the Widget tree (your code), the Element tree (manages lifecycle), and the RenderObject tree (does actual layout and painting). You only write the Widget tree; Flutter handles the rest.
Code example
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Widget Demo',
theme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.flutter_dash, size: 64),
SizedBox(height: 16),
Text('Everything is a Widget!'),
],
),
),
);
}
}Line-by-line walkthrough
- 1. Import the Flutter material design library
- 2. Define MyApp as a StatelessWidget -- the root of our app
- 3. Add const constructor with super.key for widget identity
- 4. Override build method which receives BuildContext
- 5. Return MaterialApp widget -- this is the root of the widget tree
- 6. Set the app title to Widget Demo
- 7. Configure the theme with a blue color scheme and Material 3
- 8. Set HomeScreen as the home route -- the first screen users see
- 9. Define HomeScreen as a StatelessWidget with const constructor
- 10. Override build to describe the home screen's UI
- 11. Return Scaffold -- provides basic app structure with app bar and body
- 12. Create an AppBar with a Text title widget
- 13. Set the body to a Center widget which centers its child
- 14. Inside Center, use a Column to stack children vertically
- 15. Set mainAxisAlignment to center so children are vertically centered
- 16. Add a Flutter Dash icon with size 64
- 17. Add a SizedBox with height 16 for spacing between icon and text
- 18. Add a Text widget displaying our message
Spot the bug
class MyWidget extends StatelessWidget {
String title = 'Hello';
@override
Widget build(BuildContext context) {
return Text(title);
}
}Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Introduction to Widgets (docs.flutter.dev)
- Widget Catalog (docs.flutter.dev)
- Flutter Widget of the Week (YouTube - Flutter)