Skip to content
Boring Doc
BreakingHigh impactOfficial migration guidesince 3.27.0landed 3.26.0-0.1.pre

Color wide gamut support

Framework · Official source

The API for the `Color` class in `dart:ui` is changing to support wide gamut color spaces.

Original behavior

The Flutter engine already supports wide gamut color with Impeller, and the support is now being added to the framework.

New behavior

Changes to `Color`:

Who is affected
Applications and packages relying on the previous behaviour or signature. Code that uses Color, ColorSpace, Color.fromARGB and related APIs.
Practical impact
Behaviour or API differences that can break builds or change runtime behaviour.
What action should I take?
Follow the official migration guide below, update affected call sites, run `dart fix --apply` where a fix is available, then run your tests.
Official migration guide (excerpt, © The Flutter Authors, CC BY 3.0)

8-bit unsigned integer constructors

Constructors like Color.fromARGB remain unchanged and have continued support. To take advantage of Display P3 colors, you must use the new Color.from constructor that takes normalized floating-point color components.

// Before: Constructing an sRGB color from the lower 8 bits of four integers.
final magenta = Color.fromARGB(0xff, 0xff, 0x0, 0xff);

// After: Constructing a color with normalized floating-point components.
final magenta = Color.from(alpha: 1.0, red: 1.0, green: 0.0, blue: 1.0);

Implementors of Color

There are new methods being added to Color so any class that implements Color will break and have to implement the new methods, such as Color.a and Color.b.

Ultimately, implementors should migrate to take advantage of the new API. In the short-term, these methods can easily be implemented without changing the underlying structure of your class.

For example:

class Foo implements Color {
  int _red;

  @override
  double get r => _red / 255.0;
}

Now might be a good opportunity to switch from [inheritance to composition][] and stop reimplementing Color.

Clients that use Color and perform any sort of calculation on the color components should now first check the color space component before performing calculations. To help with that, you can use the new Color.withValues method to perform color space conversions.

Example migration:

// Before
double redRatio(Color x, Color y) => x.red / y.red;

// After
double redRatio(Color x, Color y) {
  final xPrime = x.withValues(colorSpace: ColorSpace.extendedSRGB);
  final yPrime = y.withValues(colorSpace: ColorSpace.extendedSRGB);
  return xPrime.r / yPrime.r;
}

Performing calculations with color components without aligning color spaces can lead to subtle unexpected results. In the preceding example, the redRatio would have the difference of 0.09 when calculated with differing color spaces versus aligned color spaces.

Access color components

If your app ever accesses a Color component, consider taking advantage of the floating-point components. In the short term, you can scale the components themselves.

extension IntColorComponents on Color {
  int get intAlpha => _floatToInt8(this.a);
  int get intRed => _floatToInt8(this.r);
  int get intGreen => _floatToInt8(this.g);
  int get intBlue => _floatToInt8(this.b);

  int _floatToInt8(double x) {
    return (x * 255.0).round() & 0xff;
  }
}

Opacity

Before Flutter 3.27, Color had the concept of "opacity" which showed up in the methods opacity and withOpacity(). Opacity was introduced as a way to communicate with Color about its alpha channel with floating-point values ([0.0, 1.0]). Opacity methods were convenience methods for setting the 8-bit alpha value ([0, 255]), but never offered the full expression of a floating-point number. This was sufficient when color components were stored as 8-bit integers.

Since Flutter 3.27, alpha is stored as a floating-point value. Using .a and .withValues() will give the full expression of a floating-point value and won't be quantized (restricted to a limited range). That means "alpha" expresses the intent of "opacity" more correctly. Opacity is different in a subtle way where its usage can result in unexpected data loss, so .withOpacity() and .opacity have been deprecated and their semantics have been maintained to avoid breaking anyone.

For example:

// Prints 0.5019607843137255.
print(Colors.black.withOpacity(0.5).a);
// Prints 0.5.
print(Colors.black.withValues(alpha: 0.5).a);

Practically all usage will directly benefit from the more accurate colors. In the rare case where it doesn't, care can be taken to quantize opacity to [0, 255] using .alpha and .withAlpha() to match the behavior before Flutter 3.27.

Migrate opacity

// Before: Access the alpha channel as a (converted) floating-point value.
final x = color.opacity;

// After: Access the alpha channel directly.
final x = color.a;

Migrate withOpacity

// Before: Create a new color with the specified opacity.
final x = color.withOpacity(0.0);

// After: Create a new color with the specified alpha channel value,
// accounting for the current or specified color space.
final x = color.withValues(alpha: 0.0);

Equality

Once Color stores its color components as floating-point numbers, equality works slightly differently. When calculating colors, there might be a tiny difference in values that could be considered equal. To accommodate this use the [closeTo][] or [isColorSameAs][] matchers.

// Before: Check exact equality of int-based color.
expect(calculateColor(), const Color(0xffff00ff));

// After: Check rough equality of floating-point-based color.
expect(calculateColor(), isSameColorAs(const Color(0xffff00ff)));
Migration assistantAI-generated · grounded in cited sources
AI explanations are not configured
Set AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.
Official migration guide·Verified classification (95%)

Listed in the official breaking-changes index (docs.flutter.dev/release/breaking-changes).

An official announcement or migration guide documents an intended behaviour or API change. A verified source change (git diff) shows code changed but does not by itself prove a public API is breaking. AI interpretations are labelled and never used to classify a change.

Source commit
b3045439b7c0
Source last updated
Oct 21, 2026
Last synchronized
Oct 21, 2026
Publication status
published
Publication history
  • Oct 21, 2026, 8:31 PM: new → published (ingestion) — Backed by an official breaking-change/migration guide.
AI explanationAI-generated · grounded in cited sources
AI explanations are not configured
Set AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.
Was this useful?