Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

secondman's avatar

Colors in SVG's with Tailwind

Is it not possible to colorize svgs when you call them as an image?

<img src="/storage/img/icons/outline/desktop-computer.svg" class="w-auto h-6 mr-3 stroke-current" />

This sits within an intertia-link so the color should be inherited from the link class ie: text-white, but I've also tried adding the text-white class directly on the img class ... no love.

Of course adding classes to an inline svg seems to work fine ... but I prefer the cleaner code of using an image. Since Heroicons are now available to download I wanted to convert over my app to use them via image.

Any help or tips appreciated.

0 likes
5 replies
rodrigo.pedra's avatar
Level 56

No, it is not possible.

A SVG file loaded thorugh the <img> element is treated as an external resource, like any other image format, so you can't use CSS or JavaScript from the HTML document to manipulate its content.

https://stackoverflow.com/a/22253046

https://css-tricks.com/using-svg/#the-problem-with-both-img-and-background-image

Of course you could play with CSS filters to change its color as you could with another image format loaded through the <img> tag. This actually changes the rendering of the <img> element not its loaded content.

You can also apply a <style> tag in the SVG document itself to style it directly. Or add attributes to SVG's elements you want to change appearance. The this styles would be loaded when using it as an external image from <img>. But both options require changing the SVG file itself and using raw CSS and SVG attributes instead of tailwind.

If you want to style your SVG using the same CSS/Tailwind avaiable in your HTML document use it inline.

secondman's avatar

Thanks so much Rodrigo, great explanation.

Perhaps I'll create a vue component with all the svgs and pass in my styles as props. That would give me basically the same one line approach.

<heroicon :type="desktop-computer" :color="text-white" class="w-auto h-6 mr-3" />

Thanks again for your help.

1 like
rodrigo.pedra's avatar

Yes that would clean up your templates a bit.

I also don't like to inline SVGs, as they pollute the code too much. I often reach for a similar approach.

Have a nice day =)

1 like
secondman's avatar

Hey Rodrigo ...

This turned out to be surprisingly easy with a little help from html-loader

I moved my Icons folder inside my @ alias (js/components) then the component looks like so:

<template>
    <div v-html="require(`!!html-loader!@/Icons/${type}/${icon}.svg`)"></div>
</template>

<script>
export default {
    props: ['icon', 'type'],
    mounted() {
        this.$el.firstChild.classList.add(...this.$el.className.split(' '));
        this.$el.outerHTML = this.$el.innerHTML;
    }
}
</script>

then to import the icon:

<svg-icon 
    type="outline" 
    icon="desktop-computer" 
    class="w-auto h-4 mr-3 transition duration-150 ease-in-out stroke-current" 
/>

It seems to work well with any flavor of svg icons.

@calebporzio wrote a good article on this process and then there's a great gist with fantastic techniques in the comments.

article: https://calebporzio.com/using-inline-svgs-in-vue-compoments/ gist: https://gist.github.com/calebporzio/623c536f7fff77861b8a37ec11a1d3da

Have a good one man.

V

1 like
rodrigo.pedra's avatar

Nice to learn about that, thanks!

I usually reach for this package:

https://github.com/visualfanatic/vue-svg-loader

That allows you to use SVGs as components:

<template>
    <div>
        <Icon class="w-auto h-4 mr-3 transition duration-150 ease-in-out stroke-current" />
        ... other content
    </div>
</template>

<script>
import Icon from '@/icons/outline/desktop-computer.svg';

export default {
    components: {Icon},
}
</script>

But that requires a bit of additional configuration to work with babel/webpack/laravel-mix

I actually made a Mix plugin, based on some other that is listed on laravel-mix site, can't remember which. I made a "fork"/copy because I needed it work with IE 11 for a project:

// ./resources/mix/mix-vue-svg-loader
const mix = require('laravel-mix');

class MixVueSVGLoader {
    name () {
        return 'svgLoader';
    }

    dependencies () {

    }

    webpackRules () {
        return {
            test: /\.svg$/,
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: ['@babel/plugin-proposal-object-rest-spread'], // IE11
                    },
                },
                {
                    loader: 'vue-svg-loader',
                    options: { svgo: false },
                },
            ],
        };
    }

    register () {
    }

    boot () {
        Mix.listen('configReady', function (config) {
            const search = [
                /(\.(png|jpe?g|gif|webp)$|^((?!font).)*\.svg$)/.toString(),
                /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/.toString(),
            ];

            config.module.rules
                .filter((rule) => search.includes(rule.test.toString()))
                .forEach((rule) => {
                    rule.exclude = /\.svg$/;
                });
        });
    }
}

mix.extend('svgLoader', new MixVueSVGLoader());

module.exports = MixVueSVGLoader;

Then in your webpack.mix.js file you require and call it:

require('./resources/mix/mix-vue-svg-loader');

const mix = require('laravel-mix');

mix.svgLoader(); // need to call to start the extension

There also some extensions listed on laravel-mix site that might be handy:

https://laravel-mix.com/extensions

Have a nice day =)

Please or to participate in this conversation.