Svelte & Font Awesome Icons

I needed a way to use Font Awesome with Svelte / SvelteKit.

The Font Awesome docs did not have a Svelte example, so I set out to build my own.

The criteria I wanted for the implementation were:

  • One-line import for icons
  • Compatible with Tailwind
  • Easily extendable
  • Should work with both free and pro versions

Dependencies

To start out, we need Font Awesome. You can add whatever Font Awesome icon packs you want.

pnpm add @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/free-brands-svg-icons

Font Component

The Svelte component below uses @fortawesome/fontawesome-svg-core to render SVG icons, removes the default Font Awesome CSS, and passes Tailwind classes to the SVG element.

// lib/icon/icon.svelte

<svelte:options namespace="svg" />

<script lang="ts" module>
	// Configure font awesome
	import { config, type IconDefinition } from '@fortawesome/fontawesome-svg-core';
	config.autoAddCss = false;
	config.keepOriginalSource = false;
	config.showMissingIcons = false;
</script>

<script lang="ts">
	import { icon as iconRender } from '@fortawesome/fontawesome-svg-core';

	interface IconProps {
		icon: IconDefinition;
		class?: string;
	}
	let { icon, class: className }: IconProps = $props();
	let iconRendered = $derived(
		iconRender(icon, {
			classes: className ? [className] : []
		}).html
	);
</script>

<!-- eslint-disable svelte/no-at-html-tags -->
{@html iconRendered}

We then need a tiny bit of css to set the defaults.

// lib/icon/icon.css

@layer base {
  .svg-inline--fa {
    display: inline-block;
    height: 1em;
    overflow: visible;
    vertical-align: -0.125em;
  }
}
// app.css
@import 'tailwindcss';
@import './lib/icon/icon.css';

The export file

An index.ts file exports all the icons you want to have available, as well as the icon.svelte component created above.

I will also explain below why we export the IconDefinition type.

// /lib/icon/index.ts

import type { IconDefinition } from '@fortawesome/fontawesome-svg-core'
export type { IconDefinition }

export * from '@fortawesome/free-solid-svg-icons'

export {
  faFacebook,
  faInstagram,
  faLinkedin,
  faVimeo,
  faYoutube,
} from '@fortawesome/free-brands-svg-icons'

export { default as Icon } from './icon.svelte'

How to use it

Since we have exported all the free icons plus a few from the brands, we only need a single import from $lib/icon:

<script lang="ts">
	import { Icon, faGrimace, faLaughWink, faSmile } from '$lib/icon';
</script>

<Icon icon={faSmile} /> The simplest icon will use the inherited font size.
<Icon class="text-2xl" icon={faGrimace} /> Use Tailwind to override the font size, making it bigger.
<Icon class="text-[48px] text-red-600" icon={faLaughWink} /> Set a specific size and color.

How to pass icons as props

By typing a prop as IconDefinition, we can pass the exported icons to it.

// lib/icon-button.svelte

<script lang="ts">
  import type { Snippet } from 'svelte'
  import type { HTMLButtonAttributes } from 'svelte/elements'
  import { Icon, type IconDefinition } from '$lib/icon'

  interface IconButtonProps extends HTMLButtonAttributes {
    icon: IconDefinition
    children: Snippet
  }
  let { icon, children, class: className, ...props }: IconButtonProps = $props()
</script>

<button
  type="button"
  {...props}
  class=[
		'flex items-center justify-between gap-2',
		'rounded-lg bg-neutral-200 px-4 py-2 hover:bg-neutral-300',
		className
	]
>
  <Icon {icon} />
  {@render children()}
</button>
// routes/+page.svelte

<script lang="ts">
  import IconButton from '$lib/icon-button.svelte';
  import { faSmile } from '$lib/icon';
</script>

<IconButton icon={faSmile}>My Button</IconButton>

Demo

I have created a demo to showcase how it works:

https://github.com/leon/blog-svelte-fontawesome-icons

Font Awesome 7

Font Awesome 7 is going to be released in July 2025, bringing many new icons and improved designs. All SVGs are now square (512x512), ensuring consistent spacing and alignment. Keep an eye out here: https://fontawesome.com/