Flutter Widgets Fundamentals

Container & Decoration

45 min Lesson 7 of 18

The Container Widget

The Container widget is one of the most versatile and frequently used widgets in Flutter. It combines common painting, positioning, and sizing capabilities into a single convenient widget. A Container can apply padding, margins, borders, background colors, gradients, shadows, and transforms to its child.

Think of Container as a div in HTML/CSS -- it is the general-purpose box you use to style and position content.

Basic Container

Container(
  width: 200,
  height: 100,
  color: Colors.blue,
  child: const Center(
    child: Text(
      'Hello Container',
      style: TextStyle(color: Colors.white),
    ),
  ),
)

Key Container properties:

  • width / height -- Fixed dimensions for the container.
  • color -- Background color (cannot be used with decoration).
  • padding -- Space inside the container, between the border and the child.
  • margin -- Space outside the container, between the container and its parent.
  • alignment -- How to align the child within the container.
  • constraints -- Additional size constraints (min/max width and height).
  • decoration -- A BoxDecoration for advanced styling (replaces color).
  • transform -- A matrix transformation applied to the container.
Warning: You cannot use both color and decoration on the same Container. If you need a background color along with borders or other decoration, set the color inside the BoxDecoration instead.

Padding vs Margin

Understanding the difference between padding and margin is crucial for layout:

  • Padding -- Space inside the container, between the container’s boundary and its child.
  • Margin -- Space outside the container, between the container and surrounding widgets.

Padding vs Margin

Container(
  // Space outside (pushes away from parent/siblings)
  margin: const EdgeInsets.all(20),

  // Space inside (pushes child inward)
  padding: const EdgeInsets.all(16),

  color: Colors.blue[100],
  child: const Text('I have margin and padding'),
)

// EdgeInsets options:
// EdgeInsets.all(8)              - same on all sides
// EdgeInsets.symmetric(horizontal: 16, vertical: 8)
// EdgeInsets.only(left: 10, top: 20)
// EdgeInsets.fromLTRB(10, 20, 10, 20)  - left, top, right, bottom

BoxDecoration Deep Dive

BoxDecoration is the powerhouse of Container styling. It provides fine-grained control over the container’s visual appearance including colors, gradients, borders, rounded corners, shadows, and background images.

BoxDecoration Properties Overview

Container(
  width: 200,
  height: 200,
  decoration: BoxDecoration(
    // Background color
    color: Colors.white,

    // Rounded corners
    borderRadius: BorderRadius.circular(16),

    // Border
    border: Border.all(
      color: Colors.blue,
      width: 2,
    ),

    // Shadow
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.2),
        blurRadius: 10,
        offset: const Offset(0, 4),
      ),
    ],
  ),
  child: const Center(
    child: Text('Decorated Box'),
  ),
)

Gradient Backgrounds

BoxDecoration supports three types of gradients: LinearGradient, RadialGradient, and SweepGradient.

Gradient Types

// Linear Gradient
Container(
  width: 300,
  height: 150,
  decoration: BoxDecoration(
    gradient: const LinearGradient(
      colors: [Colors.purple, Colors.blue, Colors.cyan],
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
    ),
    borderRadius: BorderRadius.circular(12),
  ),
)

// Radial Gradient
Container(
  width: 200,
  height: 200,
  decoration: BoxDecoration(
    gradient: RadialGradient(
      colors: [Colors.yellow, Colors.orange, Colors.red],
      radius: 0.8,
    ),
    shape: BoxShape.circle,
  ),
)

// Sweep Gradient
Container(
  width: 200,
  height: 200,
  decoration: const BoxDecoration(
    gradient: SweepGradient(
      colors: [
        Colors.red,
        Colors.orange,
        Colors.yellow,
        Colors.green,
        Colors.blue,
        Colors.purple,
        Colors.red,
      ],
    ),
    shape: BoxShape.circle,
  ),
)

Border Styles

You can apply uniform borders or different borders on each side:

Border Examples

// Uniform border
Container(
  decoration: BoxDecoration(
    border: Border.all(color: Colors.blue, width: 2),
    borderRadius: BorderRadius.circular(8),
  ),
)

// Different borders per side
Container(
  decoration: const BoxDecoration(
    border: Border(
      top: BorderSide(color: Colors.red, width: 3),
      bottom: BorderSide(color: Colors.blue, width: 3),
      left: BorderSide(color: Colors.green, width: 1),
      right: BorderSide(color: Colors.green, width: 1),
    ),
  ),
)

// Only bottom border (like an underline)
Container(
  decoration: const BoxDecoration(
    border: Border(
      bottom: BorderSide(color: Colors.grey, width: 1),
    ),
  ),
)
Note: When using different borders per side (the Border() constructor), you cannot use borderRadius. Rounded corners only work with uniform borders created by Border.all().

Box Shadows

The boxShadow property accepts a list of BoxShadow objects, allowing multiple shadows for complex effects:

Shadow Examples

// Single subtle shadow
Container(
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(12),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.1),
        blurRadius: 8,
        offset: const Offset(0, 2),
      ),
    ],
  ),
)

// Multiple shadows for depth
Container(
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(16),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.1),
        blurRadius: 20,
        offset: const Offset(0, 10),
      ),
      BoxShadow(
        color: Colors.black.withOpacity(0.05),
        blurRadius: 6,
        offset: const Offset(0, 3),
      ),
    ],
  ),
)

Shape: Circle vs Rectangle

The shape property can be BoxShape.rectangle (default) or BoxShape.circle:

Circular Container

// Circular avatar-style container
Container(
  width: 100,
  height: 100,
  decoration: BoxDecoration(
    shape: BoxShape.circle,
    color: Colors.blue,
    border: Border.all(color: Colors.white, width: 3),
    boxShadow: [
      BoxShadow(
        color: Colors.blue.withOpacity(0.3),
        blurRadius: 12,
        offset: const Offset(0, 4),
      ),
    ],
  ),
  child: const Center(
    child: Text(
      'AB',
      style: TextStyle(
        color: Colors.white,
        fontSize: 32,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
)
Warning: When using BoxShape.circle, do not set borderRadius -- it will throw an error. The circle shape automatically clips the container to a circle. Also ensure the Container has equal width and height for a perfect circle.

Background Image

The image property of BoxDecoration allows you to set a background image:

Container with Background Image

Container(
  width: 300,
  height: 200,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(16),
    image: const DecorationImage(
      image: NetworkImage('https://picsum.photos/300/200'),
      fit: BoxFit.cover,
    ),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.3),
        blurRadius: 10,
        offset: const Offset(0, 5),
      ),
    ],
  ),
  child: Container(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(16),
      gradient: LinearGradient(
        colors: [
          Colors.black.withOpacity(0.6),
          Colors.transparent,
        ],
        begin: Alignment.bottomCenter,
        end: Alignment.topCenter,
      ),
    ),
    padding: const EdgeInsets.all(16),
    alignment: Alignment.bottomLeft,
    child: const Text(
      'Image with Overlay',
      style: TextStyle(
        color: Colors.white,
        fontSize: 18,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
)

Container Constraints

The constraints property accepts a BoxConstraints object that sets minimum and maximum dimensions:

Using Constraints

Container(
  constraints: const BoxConstraints(
    minWidth: 100,
    maxWidth: 300,
    minHeight: 50,
    maxHeight: 200,
  ),
  padding: const EdgeInsets.all(16),
  decoration: BoxDecoration(
    color: Colors.teal[50],
    borderRadius: BorderRadius.circular(8),
    border: Border.all(color: Colors.teal),
  ),
  child: const Text(
    'This container adapts its size based on content, '
    'but stays within the specified constraints.',
  ),
)

Container Transform

The transform property applies a Matrix4 transformation to the container. This is useful for rotations, scaling, and translations.

Transform Examples

// Rotation
Container(
  width: 100,
  height: 100,
  transform: Matrix4.rotationZ(0.1), // radians
  decoration: BoxDecoration(
    color: Colors.orange,
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Center(child: Text('Tilted')),
)

// Scale
Container(
  width: 100,
  height: 100,
  transform: Matrix4.diagonal3Values(1.2, 1.2, 1),
  transformAlignment: Alignment.center,
  decoration: BoxDecoration(
    color: Colors.purple,
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Center(
    child: Text('Scaled', style: TextStyle(color: Colors.white)),
  ),
)
Tip: Use transformAlignment (available in Flutter 3.x) to set the origin point of the transformation. By default, transforms are applied from the top-left corner, which can produce unexpected results for rotations.

DecoratedBox Widget

If you only need decoration without sizing or padding, use DecoratedBox directly instead of Container. It is a lighter widget that only applies a BoxDecoration:

DecoratedBox vs Container

// DecoratedBox - lightweight, decoration only
const DecoratedBox(
  decoration: BoxDecoration(
    color: Colors.amber,
    borderRadius: BorderRadius.all(Radius.circular(8)),
  ),
  child: Padding(
    padding: EdgeInsets.all(16),
    child: Text('Using DecoratedBox'),
  ),
)

// Container does the same but with more overhead
Container(
  padding: const EdgeInsets.all(16),
  decoration: BoxDecoration(
    color: Colors.amber,
    borderRadius: BorderRadius.circular(8),
  ),
  child: const Text('Using Container'),
)

Practical Examples

Styled Card

Custom Styled Card

Container(
  margin: const EdgeInsets.all(16),
  padding: const EdgeInsets.all(20),
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(16),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.08),
        blurRadius: 16,
        offset: const Offset(0, 4),
      ),
    ],
  ),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    mainAxisSize: MainAxisSize.min,
    children: [
      Row(
        children: [
          Container(
            width: 48,
            height: 48,
            decoration: BoxDecoration(
              color: Colors.blue[50],
              borderRadius: BorderRadius.circular(12),
            ),
            child: Icon(Icons.star, color: Colors.blue[600]),
          ),
          const SizedBox(width: 12),
          const Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Premium Plan',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              Text(
                '\$9.99/month',
                style: TextStyle(color: Colors.grey),
              ),
            ],
          ),
        ],
      ),
      const SizedBox(height: 16),
      const Text(
        'Unlock all features and get unlimited access.',
      ),
    ],
  ),
)

Circular Avatar

Custom Circular Avatar

Container(
  width: 120,
  height: 120,
  decoration: BoxDecoration(
    shape: BoxShape.circle,
    gradient: const LinearGradient(
      colors: [Colors.purple, Colors.deepOrange],
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
    ),
    border: Border.all(color: Colors.white, width: 4),
    boxShadow: [
      BoxShadow(
        color: Colors.purple.withOpacity(0.4),
        blurRadius: 20,
        offset: const Offset(0, 8),
      ),
    ],
  ),
  child: const Center(
    child: Text(
      'ES',
      style: TextStyle(
        color: Colors.white,
        fontSize: 40,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
)

Practice Exercise

Create a profile card using Container and BoxDecoration that includes: (1) A gradient background from top-left to bottom-right. (2) Rounded corners with a radius of 20. (3) A subtle shadow with blur radius 15 and vertical offset 6. (4) Inside: a circular avatar Container at the top, a name Text, and a description Text. (5) The avatar should have a white border and a circular gradient. Challenge: Add a transform to slightly tilt the card and use DecorationImage for a background pattern.