Flutter Widgets — the basic building blocks of the user interface in the Google Flutter framework, released in stable version 1.0 in December 2018. In Flutter, everything is a widget: from screens and buttons to padding and alignment. Widgets form a widget tree, which Flutter renders on its own Skia/Impeller engine, bypassing native platform components. According to Google I/O (2025), Flutter is used in over 500,000 apps on Google Play and the App Store. The Flutter architecture divides widgets into StatelessWidget (immutable) and StatefulWidget (with mutable state via a State object).
Key Takeaways
Flutter Widgets — all UI elements in the Flutter framework, implemented as immutable Dart classes. A widget is a configuration of a UI element: its size, color, position, and event handlers. Unlike Android (XML + View) or iOS (Storyboard + UIView), Flutter does not use native components — everything is drawn by the Skia engine (Android/iOS/Linux) or Impeller (iOS/macOS) on a Canvas. This ensures a consistent look across all platforms without platform discrepancies. Flutter ships with two sets of widgets: Material Widgets (Google Material Design 3 for Android/web) and Cupertino Widgets (Apple HIG for iOS/macOS). Developers can combine both sets in a single application. Each widget has a build() method that returns a child widget or a composition of them — this is how the widget tree is built.
Flutter operates with three trees: Widget Tree (configuration, created by the developer), Element Tree (mapping a widget to its position in the tree, managed by the framework), and Render Tree (objects that compute layout and perform painting). A Widget creates an Element, which creates a RenderObject. An Element is reused when the configuration changes (rebuild) — this is Flutter's optimization mechanism: if the widget type and key match, the Element is not recreated, but updated with the new configuration. Understanding the three trees is key to optimizing Flutter application performance.
StatelessWidget — a widget that does not store internal state. It receives parameters through the constructor and displays them without the ability to change after build. StatelessWidget is ideal for static elements: headers, icons, avatars, lists with fixed data. The build() method is called once at creation and when the parent widget changes. Since StatelessWidget has no state, it does not require a separate State object — build() is defined directly in the widget class.
import 'package:flutter/material.dart';
class ProfileHeader extends StatelessWidget {
final String name;
final String avatarUrl;
const ProfileHeader({super.key, required this.name, required this.avatarUrl});
@override
Widget build(BuildContext context) {
return Row(
children: [
CircleAvatar(
radius: 24,
backgroundImage: NetworkImage(avatarUrl),
),
const SizedBox(width: 12),
Text(
name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
);
}
}ProfileHeader — a StatelessWidget that accepts name and avatarUrl through the constructor. CircleAvatar displays the avatar, Text displays the name. The widget cannot change these values after creation. Using a const constructor (const ProfileHeader) allows Flutter to reuse the widget instance during parent rebuild — a micro-optimization recommended for all StatelessWidgets.
StatefulWidget — a widget with mutable state stored in a separate State object. The StatefulWidget itself is immutable, like StatelessWidget. The mutable part is delegated to State: State is an object created once and survives multiple widget rebuilds. When the state changes (setState()), Flutter calls build() on the State, updating the UI. StatefulWidget is used for interactive elements: counters, text fields, checkboxes, animations, timers.
import 'package:flutter/material.dart';
class LikeButton extends StatefulWidget {
const LikeButton({super.key});
@override
State<LikeButton> createState() => _LikeButtonState();
}
class _LikeButtonState extends State<LikeButton> {
bool liked = false;
int count = 42;
void _toggleLike() {
setState(() {
liked = !liked;
count += liked ? 1 : -1;
});
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _toggleLike,
child: Text(liked ? '♥ $count' : '♡ $count'),
);
}
}LikeButton — a StatefulWidget with the State class _LikeButtonState. The fields liked and count are state stored in State and are not reset on rebuild. setState() notifies Flutter that the UI needs to be rebuilt. Flutter does not recreate State on every parent rebuild — only when the configuration changes (key or widget type). At IT Sectr, we use StatelessWidget for display and StatefulWidget for interactive components, following the principle of minimizing StatefulWidget to the boundaries of mutation.
Widget Tree — a hierarchical structure of widgets describing the application UI. Flutter converts the Widget Tree into an Element Tree: each Widget creates an Element, which tracks its position in the tree and its connection to a RenderObject. The Render Tree performs layout (determining sizes and positions) and paint (rendering). The Element is a key optimization layer: if the widget type and key have not changed during a rebuild, the Element is reused, updating the configuration without recreating the RenderObject. This ensures Flutter's performance at high frame rates (60/120 FPS).
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter Widgets')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.flutter_dash, size: 80),
const SizedBox(height: 16),
const Text(
'Hello, Flutter!',
style: TextStyle(fontSize: 24),
),
],
),
),
);
}
}HomeScreen widget tree: Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold is the root Material Design layout widget. Center centers its child Column. Column arranges children vertically with center alignment (mainAxisAlignment.center). Flutter computes layout top-down (constraints are passed from parent) and sizes bottom-up (sizedByParent or sizing from children).
BuildContext — a descriptor of the widget's position in the Element Tree. Each build() method receives a BuildContext, through which the widget can access: MediaQuery (screen size, orientation, pixel density, safe area), Theme (MaterialThemeData or CupertinoThemeData), Navigator (navigation stack), ScaffoldMessenger (SnackBar), InheritedWidget (passing data down the tree). BuildContext should not be saved after build() completes or used outside of a synchronous context — this leads to errors like “Scaffold.of() called with a context that does not contain a Scaffold”. Instead of saving context, use the Builder widget or the InheritedWidget pattern for data access.
Key — an optional constructor parameter for every widget (super.key). Key helps Flutter identify a widget when the order or number of items in a list changes. Without a key, Flutter compares widgets by type and position; when an item is added to the middle of a list without a key, Flutter reuses the Element for the wrong widget, causing state bugs (StatefulWidget) and animation issues. Use ValueKey (unique identifier) for lists, ObjectKey (based on data object), UniqueKey (guaranteed unique on every rebuild — for forced recreation).
Flutter SDK (stable version 3.3+, Dart 3+) includes 200+ built-in widgets divided into categories: Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView), Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable), Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar), Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask), Async (FutureBuilder, StreamBuilder) and Accessibility (Semantics, MergeSemantics, ExcludeSemantics). Layout widgets are the foundation of any Flutter UI: Row for horizontal sequences, Column for vertical, Stack for overlapping elements, Container with BoxDecoration for decoration.
| Category | Key Widgets | Purpose |
|---|---|---|
| Layout | Row, Column, Stack, Container, Expanded, Flexible | Positioning and sizing of child elements |
| Material | Scaffold, AppBar, Card, Drawer, FAB, TabBar | Material Design 3 UI components |
| Cupertino | CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton | iOS-styled components |
| Painting | Opacity, ClipRect, Transform, DecoratedBox, BackdropFilter | Visual effects and clipping |
| Async | FutureBuilder, StreamBuilder | Async data loading with UI states |
| Accessibility | Semantics, MergeSemantics | Semantic markup for screen readers |
Frequently Asked Questions
StatelessWidget has no internal state — all data is passed through the constructor and does not change. StatefulWidget stores mutable state in a separate State object that survives rebuilds. Changing the state calls setState(), and Flutter rebuilds the UI. Use StatelessWidget for immutable elements; use StatefulWidget for interactive ones.
BuildContext is a descriptor of the widget's position in the Element Tree, passed to the build() method. Through context, a widget accesses MediaQuery, Theme, Navigator, ScaffoldMessenger, and InheritedWidget. BuildContext should not be saved after build() completes. For data access, use the Builder widget or InheritedWidget.
Yes, Flutter uses Dart as its sole programming language. Dart is a statically typed language with null safety, sound null safety, extension methods, and pattern matching. To get started, basic Dart knowledge is sufficient: classes, functions, async/await, collections. Dart compiles to native code (AOT) via Dart Native and to JavaScript (for the web) via Dart2JS.
No, Flutter supports six platforms: iOS, Android, Web, macOS, Windows, Linux. Over 90% of code is shared across all platforms. Platform adaptations (camera, file system) are implemented through plugins or platform channels. For desktop, Flutter uses the Flutter Desktop windowing shell; for web, it uses the CanvasKit (WebGL) or HTML renderer.
Flutter achieves 60/120 FPS through: its own 2D engine (Skia/Impeller), the absence of a native bridge (unlike React Native), three trees (Widget → Element → Render) with Element reuse when type/key remain unchanged, a layout algorithm with a unidirectional pass (constraints down, sizes up), and RepaintBoundary for isolating repainting of individual screen areas.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also