# Flutter Core Widgets — Part 1

> Source: <https://dev.to/gochev/flutter-core-widgets-part-1-4pdh>
> Published: 2026-07-07 09:25:07+00:00

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" give it time to load, it takes about 5-10 seconds.

Displays a string of styled text.

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

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

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)),
    ],
  ),
)
```

**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.

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

```
Image.network(
  'https://picsum.photos/200',
  width: 200,
  height: 200,
  fit: BoxFit.cover,
)
```

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

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

```
Icon(Icons.favorite, color: Colors.red, size: 48)
```

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

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

``` js
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'),
)
```

**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.

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

```
SizedBox(width: 100, height: 50, child: Container(color: Colors.green))
```

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

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

```
Placeholder(fallbackWidth: 200, fallbackHeight: 100)
```

**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."

Lays children out horizontally.

```
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: const [
    Icon(Icons.star), Icon(Icons.star), Icon(Icons.star),
  ],
)
```

**How it looks:**

```
[ ★        ★        ★ ]
```

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

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'),
  ],
)
```

**How it looks:**

```
Line one
Line two
Line three
```

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

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)),
  ],
)
```

**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.

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)),
  ],
)
```

**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.

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)),
  ],
)
```

**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.

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)),
  ],
)
```

**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).

Adds empty space around a single child.

``` js
Padding(
  padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
  child: Text('Padded text'),
)
```

**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.

Centers its single child within itself.

```
Center(child: Icon(Icons.check_circle, size: 60, color: Colors.green))
```

**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.

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

```
Align(
  alignment: Alignment.bottomRight,
  child: Icon(Icons.info, size: 32),
)
```

**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.

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

``` js
Wrap(
  spacing: 8,
  runSpacing: 8,
  children: List.generate(8, (i) => Chip(label: Text('Tag $i'))),
)
```

**How it looks:**

```
[Tag 0] [Tag 1] [Tag 2] [Tag 3]
[Tag 4] [Tag 5] [Tag 6] [Tag 7]
```

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.

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

```
AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(color: Colors.black),
)
```

**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.

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

```
FractionallySizedBox(
  widthFactor: 0.5,
  heightFactor: 0.3,
  child: Container(color: Colors.purple),
)
```

**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.

A scrollable, linear list of widgets.

``` js
ListView(
  children: List.generate(20, (i) => ListTile(title: Text('Item $i'))),
)
```

**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.

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

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

**How it looks:**

```
[ ][ ][ ]
[ ][ ][ ]
[ ][ ][ ]
```

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

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

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

**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.

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

```
PageView(
  children: [
    Container(color: Colors.red),
    Container(color: Colors.green),
    Container(color: Colors.blue),
  ],
)
```

**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.

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),
)
```

**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](mailto:jane@example.com)" beneath it, and a small chevron arrow on the far right — the classic settings-menu row look.

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')))),
)
```

**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.

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

``` js
ElevatedButton(
  onPressed: () {},
  child: const Text('Submit'),
)
```

**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.

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

``` js
TextButton(
  onPressed: () {},
  child: const Text('Cancel'),
)
```

**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.

Like TextButton, but with a visible border outline.

``` js
OutlinedButton(
  onPressed: () {},
  child: const Text('Learn More'),
)
```

**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.

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

```
IconButton(
  icon: Icon(Icons.thumb_up),
  onPressed: () {},
)
```

**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.

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

``` js
FloatingActionButton(
  onPressed: () {},
  child: const Icon(Icons.add),
)
```

**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.

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

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

**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.

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

``` js
TextField(
  decoration: const InputDecoration(
    labelText: 'Email',
    border: OutlineInputBorder(),
  ),
)
```

**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.

A tappable square that toggles checked/unchecked.

```
Checkbox(value: true, onChanged: (v) {})
```

**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.

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

```
Radio<int>(value: 1, groupValue: 1, onChanged: (v) {})
```

**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.

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

```
Switch(value: true, onChanged: (v) {})
```

**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.

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

```
Slider(value: 0.6, onChanged: (v) {})
```

**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.

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

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

**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.

A container that groups multiple form fields for validation as a unit (usually wraps `TextFormField`

s).

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

**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.

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

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

**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.

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

``` js
AppBar(
  title: const Text('Dashboard'),
  actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {})],
)
```

**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.

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

``` js
Card(
  elevation: 4,
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Text('Card content'),
  ),
)
```

**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.

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')),
    ],
  ),
)
```

**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.

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'),
  ],
)
```

**How it looks:**

```
[ 🏠 Home ] [ 🔍 Search ] [ 👤 Profile ]
```

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.

A row of tabs, usually paired with a `TabBarView`

for swipeable content beneath it.

```
TabBar(
  tabs: const [Tab(text: 'Photos'), Tab(text: 'Videos')],
)
```

**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.

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

``` js
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')),
  ],
)
```

**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.

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

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

**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.

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

``` js
showModalBottomSheet(
  context: context,
  builder: (context) => Container(
    height: 200,
    child: const Center(child: Text('Bottom sheet content')),
  ),
);
```

**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.

A spinning loading indicator.

``` js
const CircularProgressIndicator()
```

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

Manages a stack of screens (routes); `push`

adds a new one, `pop`

returns to the previous.

``` js
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const DetailScreen()),
);
```

**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.

The concrete `Route`

implementation used with `Navigator`

that provides the platform-appropriate transition animation.

``` js
MaterialPageRoute(
  builder: (context) => Scaffold(
    appBar: AppBar(title: const Text('Details')),
    body: const Center(child: Text('Detail content')),
  ),
)
```

**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`

.

This covers the ~50 **core** widgets you'll reach for in almost every Flutter app.
