DEV Community

Nayden Gochev
Nayden Gochev

Posted on

Flutter Core Widgets — Part 1

Flutter Core Widgets — Part 1

A reference guide to the ~50 most-used Flutter widgets, grouped by category. Each entry includes a short description, a runnable code snippet, and a text description of how it renders on screen (since Flutter renders natively, this doc describes the visual output rather than embedding a screenshot).

**NOTE: if you are using "Open in DartPad" do not foreget to hit RUN and give it time to load, it takes about 10-15 seconds to load.


Table of Contents

  1. Basic Widgets
  2. Layout Widgets
  3. Scrolling & Lists
  4. Buttons
  5. Input & Forms
  6. Structural / Material
  7. Feedback & Overlays
  8. Navigation

1. Basic Widgets

Text

Displays a string of styled text.

Text(
  'Hello, Flutter!',
  style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A single line reading "Hello, Flutter!" in large, bold, blue lettering. No border or background — just the rendered glyphs.


RichText

Displays text with multiple styles in one block, via TextSpan children.

RichText(
  text: TextSpan(
    text: 'Hello ',
    style: TextStyle(color: Colors.black, fontSize: 20),
    children: [
      TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
      TextSpan(text: ' world', style: TextStyle(fontStyle: FontStyle.italic)),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: One continuous line — "Hello bold world" — where each segment has a different style, but they all flow together as a single sentence.


Image

Displays an image from assets, network, memory, or file.

Image.network(
  'https://picsum.photos/200',
  width: 200,
  height: 200,
  fit: BoxFit.cover,
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A 200×200 pixel square photo, cropped to fill that box exactly (no distortion, edges may be cropped).


Icon

Displays a glyph from an icon font (usually Material Icons).

Icon(Icons.favorite, color: Colors.red, size: 48)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A solid red heart shape, 48 logical pixels tall, centered in its own bounding box.


Container

A general-purpose box for padding, margin, decoration, alignment, and sizing.

Container(
  width: 150,
  height: 100,
  padding: const EdgeInsets.all(16),
  margin: const EdgeInsets.all(8),
  decoration: BoxDecoration(
    color: Colors.amber,
    borderRadius: BorderRadius.circular(12),
    boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 4, offset: Offset(2, 2))],
  ),
  child: const Text('Box'),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A rounded-corner amber rectangle (150×100) with a soft drop shadow beneath it, and the word "Box" sitting inside with 16px of breathing room on all sides.


SizedBox

Forces a child (or empty space) to an exact width/height.

SizedBox(width: 100, height: 50, child: Container(color: Colors.green))
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A flat green rectangle exactly 100 wide by 50 tall — commonly used invisibly (no child) as fixed spacing between other widgets.


Placeholder

A crosshatched box, useful while prototyping layouts before real content exists.

Placeholder(fallbackWidth: 200, fallbackHeight: 100)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A 200×100 rectangle with a thin black border and a diagonal "X" drawn corner-to-corner inside it — a visual stand-in for "content goes here."


2. Layout Widgets

Row

Lays children out horizontally.

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: const [
    Icon(Icons.star), Icon(Icons.star), Icon(Icons.star),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks:

[ ★        ★        ★ ]
Enter fullscreen mode Exit fullscreen mode

Three stars spread evenly across the full width of the row, with equal gaps on both sides and between each icon.


Column

Lays children out vertically. Same API as Row, opposite axis.

Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: const [
    Text('Line one'),
    Text('Line two'),
    Text('Line three'),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks:

Line one
Line two
Line three
Enter fullscreen mode Exit fullscreen mode

Three lines stacked top to bottom, all left-aligned.


Stack

Overlaps children on top of one another (z-axis layering).

Stack(
  alignment: Alignment.center,
  children: [
    Container(width: 150, height: 150, color: Colors.blue),
    Container(width: 100, height: 100, color: Colors.orange),
    const Text('Top', style: TextStyle(color: Colors.white)),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A large blue square, with a smaller orange square centered on top of it, and the word "Top" in white text centered above both — three layers visible as one flattened image.


Positioned

Used inside a Stack to pin a child to specific coordinates/edges.

Stack(
  children: [
    Container(width: 200, height: 200, color: Colors.grey[300]),
    Positioned(top: 10, right: 10, child: Icon(Icons.close, color: Colors.red)),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A large light-grey square with a small red "X" icon pinned to its top-right corner, 10px in from each edge.


Expanded

Inside a Row/Column, forces a child to fill the remaining available space.

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Expanded(child: Container(height: 50, color: Colors.blue)),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A small 50×50 red square on the left, followed immediately by a blue bar that stretches to fill every remaining pixel of the row's width.


Flexible

Like Expanded, but lets the child be smaller than the allotted space (FlexFit.loose by default).

Row(
  children: [
    Flexible(flex: 1, child: Container(height: 50, color: Colors.red)),
    Flexible(flex: 2, child: Container(height: 50, color: Colors.green)),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: Two colored bars side by side spanning the full row width, where the green bar is exactly twice as wide as the red one (flex ratio 1:2).


Padding

Adds empty space around a single child.

Padding(
  padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
  child: Text('Padded text'),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: The text "Padded text" with a wide empty margin on its left and right (24px) and a thinner one above/below (8px) — the text itself sits inset from wherever this widget is placed.


Center

Centers its single child within itself.

Center(child: Icon(Icons.check_circle, size: 60, color: Colors.green))
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A green checkmark-in-a-circle icon sitting exactly in the middle of the available space, regardless of how large that space is.


Align

Like Center, but lets you pick any alignment, not just the middle.

Align(
  alignment: Alignment.bottomRight,
  child: Icon(Icons.info, size: 32),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A small info icon tucked into the bottom-right corner of its parent's box, with everything above and to the left left empty.


Wrap

Like Row/Column, but automatically flows children onto new lines when space runs out.

Wrap(
  spacing: 8,
  runSpacing: 8,
  children: List.generate(8, (i) => Chip(label: Text('Tag $i'))),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks:

[Tag 0] [Tag 1] [Tag 2] [Tag 3]
[Tag 4] [Tag 5] [Tag 6] [Tag 7]
Enter fullscreen mode Exit fullscreen mode

A row of pill-shaped "chip" tags that fills the available width, then automatically wraps remaining chips onto a second line, with even spacing both between chips and between rows.


AspectRatio

Forces its child into a fixed width/height ratio (e.g., 16:9).

AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(color: Colors.black),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A black rectangle shaped exactly like a widescreen video frame (16:9) — however wide the available space is, the height auto-adjusts to keep that same proportion.


FractionallySizedBox

Sizes its child as a fraction of the parent's available space.

FractionallySizedBox(
  widthFactor: 0.5,
  heightFactor: 0.3,
  child: Container(color: Colors.purple),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A purple rectangle that always occupies exactly half the parent's width and 30% of its height — it resizes proportionally if the parent resizes.


3. Scrolling & Lists

ListView

A scrollable, linear list of widgets.

ListView(
  children: List.generate(20, (i) => ListTile(title: Text('Item $i'))),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A vertical scrolling column of rows labeled "Item 0" through "Item 19," where only the ones that fit on screen are visible at once and the rest reveal themselves as you scroll down.


GridView

A scrollable grid of widgets in a fixed number of columns (or a max tile extent).

GridView.count(
  crossAxisCount: 3,
  children: List.generate(9, (i) => Container(
    margin: const EdgeInsets.all(4),
    color: Colors.teal[100 * ((i % 8) + 1)],
  )),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks:

[ ][ ][ ]
[ ][ ][ ]
[ ][ ][ ]
Enter fullscreen mode Exit fullscreen mode

A 3×3 grid of evenly sized teal-toned squares, each with a small gap between neighbors, filling the screen edge-to-edge.


SingleChildScrollView

Makes a single (usually tall) child scrollable, when it doesn't fit on screen.

SingleChildScrollView(
  child: Column(
    children: List.generate(15, (i) => Container(height: 80, color: Colors.blueGrey[100 + i * 50 % 400])),
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A tall column of stacked colored bands, taller than the screen — the top portion is visible initially, and the whole thing scrolls up to reveal the rest.


PageView

Full-screen (or full-width) pages you swipe between horizontally.

PageView(
  children: [
    Container(color: Colors.red),
    Container(color: Colors.green),
    Container(color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: One solid-colored full-screen page at a time (red, then green, then blue), with a horizontal swipe gesture sliding the next page in from the edge.


ListTile

A standard single-row list item with optional leading/trailing icons and subtitle.

ListTile(
  leading: Icon(Icons.person),
  title: Text('Jane Doe'),
  subtitle: Text('jane@example.com'),
  trailing: Icon(Icons.arrow_forward_ios),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A single horizontal row: a person icon on the far left, "Jane Doe" in bold-ish title text with a smaller grey "jane@example.com" beneath it, and a small chevron arrow on the far right — the classic settings-menu row look.


Scrollbar

Wraps a scrollable widget to show a draggable scrollbar track.

Scrollbar(
  thumbVisibility: true,
  child: ListView(children: List.generate(30, (i) => ListTile(title: Text('Row $i')))),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: The same scrolling list as ListView, but with a thin vertical grey bar running down the right edge of the screen, whose length and position indicate how far through the list you've scrolled.


4. Buttons

ElevatedButton

A filled, raised button — the primary call-to-action button.

ElevatedButton(
  onPressed: () {},
  child: const Text('Submit'),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A solid-colored pill/rounded-rectangle button (theme color, usually a shade of blue or purple) with white "Submit" text centered inside, and a subtle shadow that makes it look slightly raised off the page.


TextButton

A flat, text-only button with no background or shadow.

TextButton(
  onPressed: () {},
  child: const Text('Cancel'),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: Just the word "Cancel" in the theme's accent color, sitting flush against the page background — no border, no fill, no shadow. Tapping shows a faint ripple.


OutlinedButton

Like TextButton, but with a visible border outline.

OutlinedButton(
  onPressed: () {},
  child: const Text('Learn More'),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A rounded-rectangle button with a thin colored border and transparent/matching-background fill, with "Learn More" text in the same accent color inside it.


IconButton

A tappable icon with built-in ripple/highlight feedback.

IconButton(
  icon: Icon(Icons.thumb_up),
  onPressed: () {},
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A plain thumbs-up icon sitting by itself; tapping it shows a soft circular ripple radiating from the icon, but there's no visible button "chrome" otherwise.


FloatingActionButton

A circular, elevated button typically anchored to a screen's bottom-right corner.

FloatingActionButton(
  onPressed: () {},
  child: const Icon(Icons.add),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A solid-colored circle (usually accent-colored) with a white "+" icon centered inside, floating above the rest of the page content with a visible drop shadow — the classic "add new item" button.


PopupMenuButton

An icon (often three dots) that reveals a dropdown menu of options when tapped.

PopupMenuButton<String>(
  itemBuilder: (context) => [
    const PopupMenuItem(value: 'edit', child: Text('Edit')),
    const PopupMenuItem(value: 'delete', child: Text('Delete')),
  ],
  onSelected: (value) {},
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A vertical three-dot icon by default; tapping it drops down a small white rounded-corner card listing "Edit" and "Delete" as tappable rows, layered above the rest of the screen with a shadow.


5. Input & Forms

TextField

A single-line (or multi-line) editable text input box.

TextField(
  decoration: const InputDecoration(
    labelText: 'Email',
    border: OutlineInputBorder(),
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A rectangular box with a thin outlined border, and a small "Email" label floating above/inside the border on the left — clicking inside shows a blinking text cursor and the label animates upward when text is entered.


Checkbox

A tappable square that toggles checked/unchecked.

Checkbox(value: true, onChanged: (v) {})
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A small square with rounded corners; when checked it's filled with the theme color and shows a white checkmark, when unchecked it's an empty outlined square.


Radio

One option among a mutually exclusive group (only one can be selected).

Radio<int>(value: 1, groupValue: 1, onChanged: (v) {})
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A small circle outline; when selected, a smaller filled dot appears centered inside it in the theme color — visually distinct from Checkbox by being round instead of square.


Switch

An on/off toggle, styled like a physical sliding switch.

Switch(value: true, onChanged: (v) {})
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A horizontal rounded pill track with a circular white "thumb" — when off, the thumb sits on the left with a grey track; when on, the thumb slides to the right and the track fills with the theme color.


Slider

Lets the user pick a value by dragging along a track.

Slider(value: 0.6, onChanged: (v) {})
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A horizontal line/track with a filled colored segment from the left up to a circular draggable "thumb" positioned at 60% along the track, and an unfilled grey segment continuing to the right.


DropdownButton

A tappable field showing a current value, which opens a list of alternatives.

DropdownButton<String>(
  value: 'A',
  items: ['A', 'B', 'C'].map((v) => DropdownMenuItem(value: v, child: Text(v))).toList(),
  onChanged: (v) {},
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: The text "A" with a small downward-pointing arrow/chevron beside it; tapping it drops a vertical menu listing "A," "B," "C" directly beneath, from which tapping one closes the menu and updates the displayed value.


Form

A container that groups multiple form fields for validation as a unit (usually wraps TextFormFields).

Form(
  key: formKey,
  child: Column(
    children: [
      TextFormField(validator: (v) => v!.isEmpty ? 'Required' : null),
      ElevatedButton(onPressed: () => formKey.currentState!.validate(), child: const Text('Submit')),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: Visually identical to its child fields stacked in a column (an outlined text box, then a Submit button below it) — but if left empty and Submit is tapped, a red "Required" error message appears beneath the field and its border turns red.


6. Structural / Material

Scaffold

The top-level page structure: provides slots for an app bar, body, floating button, drawer, bottom nav, etc.

Scaffold(
  appBar: AppBar(title: const Text('My App')),
  body: const Center(child: Text('Hello')),
  floatingActionButton: FloatingActionButton(onPressed: () {}, child: const Icon(Icons.add)),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A full screen with a colored bar across the top reading "My App," a plain white/grey body area beneath it showing "Hello" centered, and a circular "+" button floating in the bottom-right corner — the standard shape of almost every Flutter screen.


AppBar

The top navigation/title bar, usually used inside a Scaffold.

AppBar(
  title: const Text('Dashboard'),
  actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {})],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A solid-colored horizontal bar at the very top of the screen with "Dashboard" in bold white/on-theme text on the left, and a search icon aligned to the right edge.


Card

A material-styled container with rounded corners and elevation — used to group related content.

Card(
  elevation: 4,
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Text('Card content'),
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A white (or surface-color) rounded-rectangle panel with a soft drop shadow that lifts it visually off the background, containing "Card content" text with padding inset on all sides.


Drawer

A slide-in side panel, usually triggered by a hamburger icon in the AppBar.

Drawer(
  child: ListView(
    children: const [
      DrawerHeader(child: Text('Menu')),
      ListTile(title: Text('Home')),
      ListTile(title: Text('Settings')),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A panel that slides in from the left edge, covering roughly 3/4 of the screen width, with a header area reading "Menu" at the top followed by a vertical list of tappable rows ("Home," "Settings") beneath it, and a scrim darkening the rest of the screen behind it.


BottomNavigationBar

A row of tappable icon+label destinations fixed to the bottom of the screen.

BottomNavigationBar(
  currentIndex: 0,
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
    BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
    BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks:

[ 🏠 Home ] [ 🔍 Search ] [ 👤 Profile ]
Enter fullscreen mode Exit fullscreen mode

A horizontal bar fixed to the bottom of the screen with three evenly spaced icon-and-label pairs; the currently selected one ("Home") is shown in the theme's accent color while the others are grey.


TabBar

A row of tabs, usually paired with a TabBarView for swipeable content beneath it.

TabBar(
  tabs: const [Tab(text: 'Photos'), Tab(text: 'Videos')],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: Two side-by-side labels ("Photos" and "Videos") spanning the bar's width, with a colored underline indicator beneath whichever tab is currently active, which slides over when you switch tabs.


7. Feedback & Overlays

AlertDialog

A modal popup box, usually with a title, message, and action buttons.

AlertDialog(
  title: const Text('Delete item?'),
  content: const Text('This action cannot be undone.'),
  actions: [
    TextButton(onPressed: () {}, child: const Text('Cancel')),
    TextButton(onPressed: () {}, child: const Text('Delete')),
  ],
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A small white rounded-rectangle card centered on screen, with the rest of the screen dimmed behind it — "Delete item?" in bold at the top, explanatory text beneath, and two text buttons ("Cancel," "Delete") aligned to the bottom-right of the card.


SnackBar

A brief message bar that slides up from the bottom of the screen, then auto-dismisses.

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(content: const Text('Saved successfully'), action: SnackBarAction(label: 'Undo', onPressed: () {})),
);
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A dark, rounded-rectangle bar that slides up from the very bottom edge of the screen, showing "Saved successfully" in white text on the left and an "Undo" action in accent color on the right, disappearing on its own after a few seconds.


BottomSheet (showModalBottomSheet)

A panel that slides up from the bottom, covering part of the screen, for supplementary actions/content.

showModalBottomSheet(
  context: context,
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('Bottom sheet content')),
  ),
);
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: The bottom ~1/4 to 1/3 of the screen becomes a rounded-top white panel sliding up over the existing content (which dims behind it), showing "Bottom sheet content" centered inside it — swiping down or tapping outside dismisses it.


CircularProgressIndicator

A spinning loading indicator.

const CircularProgressIndicator()
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: A thin circular arc in the theme's accent color, continuously rotating in place — the standard "loading, please wait" spinner.


8. Navigation

Navigator (push / pop)

Manages a stack of screens (routes); push adds a new one, pop returns to the previous.

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const DetailScreen()),
);
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: The current screen slides out to the left while a new screen (DetailScreen) slides in from the right, fully replacing the visible content — the standard "drill into a detail page" transition on Android/iOS-style apps.


MaterialPageRoute

The concrete Route implementation used with Navigator that provides the platform-appropriate transition animation.

MaterialPageRoute(
  builder: (context) => Scaffold(
    appBar: AppBar(title: const Text('Details')),
    body: const Center(child: Text('Detail content')),
  ),
)
Enter fullscreen mode Exit fullscreen mode

▶ Open in DartPad

How it looks: Not a widget you see directly — it's the wrapper that produces the slide-in transition and back-swipe gesture behavior described above when used with Navigator.push.


What's Next

This covers the ~50 core widgets you'll reach for in almost every Flutter app. The next part can be found here https://dev.to/gochev/flutter-widgets-guide-part-2-every-other-widget-35p5

Top comments (0)