Skip to content
Blog

ClipRRect in Flutter: Rounded Corners Without the Visual Bugs

How ClipRRect clips children to rounded rectangles, when to prefer Container.borderRadius, clipBehavior trade-offs, and the patterns that avoid overflow and antialiasing artifacts.

Published on • November 4, 2026

AI Assistant

Rounded corners look trivial until a child paints outside its bounds: an image bleeds past a radius, a gradient square pokes through a circular avatar, or a row of cards renders jagged edges. ClipRRect (clip rectangle, rounded) is Flutter’s dedicated painting widget for clipping a child to a rounded rectangle (docs.flutter.dev).

The Basic Pattern

ClipRRect takes a borderRadius and a single child. Everything the child paints is clipped to that radius:

ClipRRect(
  borderRadius: BorderRadius.circular(16),
  child: Image.network(
    'https://picsum.photos/seed/profile/400/400',
    fit: BoxFit.cover,
    width: 120,
    height: 120,
  ),
)

This is the standard recipe for circular avatars, rounded thumbnails, and image cards — anywhere the child has no rounding of its own.

ClipRRect vs. Container Decoration

If the child is a Container (or DecoratedBox) you can often skip ClipRRect entirely by rounding the decoration instead:

Container(
  width: 120,
  height: 120,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(16),
    image: const DecorationImage(
      image: AssetImage('assets/hero.jpg'),
      fit: BoxFit.cover,
    ),
  ),
)

The decoration rounds the painted background, which is cheaper than a clip layer. The rule of thumb: round a decoration when the widget paints itself; reach for ClipRRect when the rounding must cut off a child that doesn’t cooperate — images, videos, transforms, or nested widgets you don’t own.

clipBehavior: The Cost You Don’t See

ClipRRect defaults to Clip.antiAlias, which adds a saved layer and antialiased path per clip. That layer has a real cost in long lists. Flutter’s performance guidance recommends Clip.none when clipping isn’t needed, and Clip.hardEdge when it is but smooth edges aren’t critical:

ClipRRect(
  borderRadius: BorderRadius.circular(12),
  clipBehavior: Clip.hardEdge, // cheaper than antiAlias
  child: const VideoPlayer(controller),
)

Reserve Clip.antiAlias for hero images and visible edges; use Clip.hardEdge for dense grids where the radius is small enough that the difference is invisible.

Uniform vs. Per-Corner Radii

Not every corner should match. Asymmetric radii are a one-liner:

ClipRRect(
  borderRadius: const BorderRadius.only(
    topLeft: Radius.circular(20),
    topRight: Radius.circular(20),
    bottomLeft: Radius.circular(4),
    bottomRight: Radius.circular(4),
  ),
  child: child,
)

This is the shape of speech bubbles, chat messages, and folder-style cards.

Gotchas Worth Knowing

  • ClipRRect clips painting, not hit testing or layout. A child can still receive taps in the transparent corner area. Wrap with BehaviorDetector-style logic or use Clip.none plus a shaped InkWell if you need the touch target to match the visual shape.
  • Antialiasing seams appear when a rounded child sits on an identically rounded parent — both clip the same pixels twice. Prefer one rounding authority per visual element.
  • Overflow errors are unrelated to clipping: a ClipRRect does not shrink its child. Fix layout with Expanded, FittedBox, or constraints first.

Round what paints itself, clip what doesn’t, and pick the cheapest clipBehavior that still looks smooth — and rounded corners stop being a source of bugs.