A disabled button that suddenly needs to look grey, a profile photo tinted sepia for a landing page, an icon that should invert its colours on hover: these are colour edits, and in SVG they all go through a single filter primitive.
<feColorMatrix> does this work directly in the browser, without an external editing tool or a second copy of the image: one tag recalculates the colour of every pixel according to the chosen formula.
Definition
<feColorMatrix> is an SVG filter primitive that recombines every pixel's red, green, blue and alpha channels through a mathematical operation. It always sits inside a <filter> element identified by an id, which is then applied to a shape or a group with the filter="url(#myId)" attribute.
The type attribute picks the operation: matrix for a free transformation with twenty values, or one of three shortcuts, saturate, hueRotate and luminanceToAlpha, each tuned through the values attribute.
Main attributes
Four attributes cover almost every common use case.
| Type value | Effect | values attribute |
|---|---|---|
matrix | Free transformation of the four channels | 20 numbers |
saturate | Lowers or raises saturation | A number between 0 and 1 |
hueRotate | Rotates hues around the colour wheel | An angle in degrees |
luminanceToAlpha | Turns brightness into transparency | No value required |
The in attribute picks which source to work on; left empty, it defaults to SourceGraphic, meaning the shape or group the filter is attached to.
Concrete rendering example
The example below draws the same icon twice: the original on the left, then the same icon desaturated on the right with type="saturate" set to zero, the visual equivalent of a button turning inactive.
<svg viewBox="0 0 240 120" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="grayscale"><feColorMatrix type="saturate" values="0" /></filter>
</defs>
<g transform="translate(20,20)">
<rect width="80" height="80" rx="14" fill="#f97316" />
<circle cx="40" cy="40" r="22" fill="#0ea5e9" />
</g>
<g transform="translate(140,20)" filter="url(#grayscale)">
<rect width="80" height="80" rx="14" fill="#f97316" />
<circle cx="40" cy="40" r="22" fill="#0ea5e9" />
</g>
</svg>The filter never touches the paths or their positions, only the colour, which makes it reversible by simply changing the values attribute.
Difference from a similar element
<feBlend> and <feColorMatrix> are often mixed up because both live inside a <filter>, but their job differs: <feColorMatrix> reworks the channels of a single source, while <feBlend> mixes two sources together, like two layers in blend mode inside an editing tool.
Another common mix-up: <feColorMatrix> is not a drop-in replacement for the CSS filter: grayscale() property. It is more verbose, but it allows combinations no single CSS property offers, such as a hue rotation paired with partial desaturation in the same primitive.
Common pitfall
By default, SVG filtering happens in the linear colour space (linearRGB), not the sRGB space the rest of the page uses. The result: the same type="saturate" values can look duller or more vivid than expected depending on the browser. To get the expected look, add color-interpolation-filters="sRGB" to the <filter> element or directly to <feColorMatrix>.
This setting stays invisible until two renders are compared side by side, which is why it catches out even people used to CSS filters.
Real-world use case
In a learning interface like Believemy's, <feColorMatrix> typically desaturates a locked lesson icon, tints a screenshot imported through <image> sepia for a web history module, or inverts colours to preview a dark theme before coding it in CSS.
- Disabled icons in a menu or a locked badge
- Sepia or black-and-white filter on an imported photo
- Quick preview of an inverted colour palette
FAQ
feColorMatrix primitives be chained in one filter?Yes, several primitives can be stacked inside the same filter element, each one reusing the previous output through the in attribute, which lets you desaturate an image and then tint it in two separate steps.
feColorMatrix work on text, or only on images?It works on anything SVG can draw, text, vector shapes or imported bitmap images, since it recolours every pixel after rendering, regardless of what the original content actually is.
The CSS filter property offers shortcuts like grayscale() or hue-rotate(), but they rely on the very same SVG primitives behind the scenes and never match the flexibility of a custom twenty-value matrix.