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)));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.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_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.