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
ClipRRectclips painting, not hit testing or layout. A child can still receive taps in the transparent corner area. Wrap withBehaviorDetector-style logic or useClip.noneplus a shapedInkWellif 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
ClipRRectdoes not shrink its child. Fix layout withExpanded,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.