DEV Community

Cover image for Heroicons blade component using javascript
Tajid Yakub
Tajid Yakub

Posted on

3 3

Heroicons blade component using javascript

<x-hero::icon name="o:users" size=32></x-hero::icon> This is how this Heroicons blade component used on a blade template, it uses namespace hero because I made a laravel package on this alternate implementation - however, we can use this without having to install a laravel package.

Anonymous Component

The component is defined in a single blade file without class association, it has a few props which control the size and the color of the icon.

@props([
    'name' => 'o:user',
    'size' => 24,
    'fill' => 'none' ,
    'stroke' => 'currentColor' ])

<svg
    id="heroIcon-{{$name}}"
    data-group="heroicons"
    data-name="{{$name}}"
    width="{{$size}}"
    height="{{$size}}"
    xmlns="http://www.w3.org/2000/svg"
    {{$attributes->merge(['class' => 'tj-heroicons'])}}
    fill="{{$fill}}" 
    viewBox="0 0 24 24" 
    stroke="{{$stroke}}"
    aria-hidden="true">
    <!-- no path -->
</svg>
Enter fullscreen mode Exit fullscreen mode

The svg tag used as a template for applying props, without any path. Paths will be populated later by javascript through window.fetch. This is done n a DOMContentLoaded event, the fetched svg file content then parsed and apply paths element inside svg in the blade component.

Fetching the svg file

The source of the svg icon should be placed inside the public directory so it is available for us to fetch. In this case, the icons is inside heroicons/icons url path.

heroicons/
├── icons/
│   ├── outline/ 
|   ├── solid/

Enter fullscreen mode Exit fullscreen mode

Displayed icon on the specific page gathered throuh querying into the data-group attribute of the svg element inside the blade component.

document.addEventListener('DOMContentLoaded', () => {
    document
        .querySelectorAll('svg[data-group="heroicons"]')
            .forEach(heroIcon => {

                let iconPropName = heroIcon.dataset.name
                let iconPropNameSplitted = iconPropName.split(":")
                let iconType = iconPropNameSplitted[0] == 'o' ? 'outline' : 'solid'
                let iconName = iconPropNameSplitted[1]
                let iconPath = `/heroicons/icons/${iconType}/${iconName}.svg`

                window.fetch(request(iconPath))
                    .then(res => {
                        if (res.ok) {
                                return res.text()
                            }
                            console.error('Failed to fetch the svg icon.')
                    })
                    .then(data =>  insertPath(data, heroIcon))
                    .catch(err => console.error(err.message))
    })
})
Enter fullscreen mode Exit fullscreen mode

The request argument supplied to window.fetch is a Request object, initiated through a function. While the insertPath function is the part where we get the paths out of the text file and inject it into heroIcon component from the array loop attached as a function argument.

 const request = (url) => {
    return new Request(url, {
        method: 'GET',
        redirect: 'follow',
        headers: {
            'Accept': 'image/svg+xml',
        },
    })
}
Enter fullscreen mode Exit fullscreen mode

The headers section can be skipped the most important part is the url and the method. It shouldn't have problem with CORS - since it is from your own front end.

const insertPath = (svgText, el) => {

    let newEl = document.createElement('div')
    newEl.innerHTML = svgText

    // Standard style
    el.style.display = 'inline'
    el.style.marginBottom = '.2rem'

    newEl.querySelectorAll('path').forEach(p => {
        el.appendChild(p)
    })
}
Enter fullscreen mode Exit fullscreen mode

I notice that some of the svg icons have more than one path, hence the forEach on the end of the function.

fetch requests and response header

Heroku

Amplify your impact where it matters most — building exceptional apps.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay