Skip to content

Conversation

@medbenmakhlouf
Copy link
Contributor

This pull request refactors the Font Awesome Angular integration to use directives as the primary mechanism for icon rendering, replacing the previous component-only approach. By shifting rendering logic into directives, icons can now be applied to any element—not just dedicated or components—resulting in a more flexible and extensible API. The update also adds new directives for duotone styling and advanced icon features, and updates documentation and tests accordingly.

Core Refactor: Directive-Based Icon Rendering

New icon rendering directives

Introduces

  • FaIconDirectivewhich encapsulate all icon rendering behavior previously held in FaIconComponent
  • FaDuotoneIconDirectivewhich encapsulate all icon rendering behavior previously held in FaDuotoneIconComponent
  • FaLayersDirectivewhich encapsulate all icon rendering behavior previously held in FaLayersComponent
  • FaLayersCounterDirectivewhich encapsulate all icon rendering behavior previously held in FaLayersCounterComponent
  • FaLayersTextDirectivewhich encapsulate all icon rendering behavior previously held in FaLayersTextComponent
  • FaStackDirectivewhich encapsulate all icon rendering behavior previously held in FaStackComponent

These directives now own all inputs, outputs, change detection, and DOM updates.
(See: src/lib/icon/icon.directive.ts, src/lib/icon/duotone-icon.directive.ts)

Example usage:

<!-- Dynamic binding -->
<span [faIcon]="isActive ? 'check' : 'xmark'"></span>
<!-- or -->
<span faIcon [icon]="isActive ? 'check' : 'xmark'"></span>

<!-- Duotone example -->
<i [faDuotoneIcon]="['fad', 'camera']" [primaryOpacity]="0.8" [secondaryOpacity]="0.4"></i>
<!-- or -->
<i faDuotoneIcon [icon]="['fad', 'camera']" [primaryOpacity]="0.8" [secondaryOpacity]="0.4"></i>

Lightweight components using hostDirectives

FaIconComponent and FaDuotoneIconComponent are now thin wrappers that attach the new directives via hostDirectives. This preserves backwards compatibility while moving all logic to the directive layer.
(See: src/lib/icon/icon.component.ts, src/lib/icon/duotone-icon.component.ts)

@Component({
  selector: 'fa-icon',
  template: '',
  hostDirectives: [FaIconDirective],
})
export class FaIconComponent {}

Module & Public API Adjustments

All new directives are declared and exported through FontAwesomeModule, making them available for both standalone and module-based Angular setups.
(src/lib/fontawesome.module.ts)

@medbenmakhlouf medbenmakhlouf changed the title Introduce directive 🛠️ A New Era for Angular Font Awesome: Directive-First Icon Rendering Refactor Nov 24, 2025
@medbenmakhlouf
Copy link
Contributor Author

@devoto13 Thanks again for merging my previous PR today! 🙌
When you have a moment, I’d love for you to take a look at this new one as well—it should make the icon API even more flexible ;)

@devoto13
Copy link
Collaborator

Thanks for the PR @medbenmakhlouf!

I was thinking about adding directives for a while, but I haven't ever found any strong use cases for this. Do you have some good practical examples of when such directive is better choice than the component?

My thinking was mostly around building a directive to put specifically on the <svg> tag. So different from what you implement here. This way some advanced use cases get moderately easier as there is no wrapper element around the SVG which causes styling issues.

@medbenmakhlouf
Copy link
Contributor Author

medbenmakhlouf commented Nov 26, 2025

@devoto13 Thanks for the thoughtful feedback! You’re right that there isn’t a strong must-have use case that absolutely requires directives — but in practice I’ve found the directive approach feels more flexible and “closer to the template,” especially in places where adding a dedicated component can feel a bit heavy.

For example, when working with tables, lists, or other structured markup, it’s convenient to place an icon directly on elements like "<tr>", "<td>," or "<span>" without introducing an extra wrapper. It reduces boilerplate and keeps the markup cleaner when the icon is only a small enhancement rather than a standalone element.

My goal isn’t to replace the existing component API but to offer an additional, lightweight option. The current usage remains fully supported; the directive-based API simply gives developers another tool when they prefer more control over their HTML structure.

Also, looking at Angular’s current direction, they recently introduced the new @angular/aria package, which is built entirely around directives rather than components. It still provides high-level functionality, but leaves full structural control to the developer.

Your idea of attaching a directive directly to the <svg> element is really interesting, and I’d love to explore that direction too — it could definitely help with styling edge cases caused by wrapper elements.

In any case, please feel free to accept or reject the PR based on what fits the library’s long-term vision. My goal is simply to offer more flexibility and match patterns that Angular developers are increasingly using.

@devoto13
Copy link
Collaborator

Thanks for sharing additional details!

I may be a bit out of touch as for what is happening in Angular ecosystem this days as I'm not using Angular daily, it's interesting to hear about the move towards the directives.

I'm still leaning towards the idea that the added benefit of this particular solution does cover the cost of the expanded API surface, but let's leave this PR open for a while and see if maybe some other users can provide additional feedback.

I'm somewhat more open towards having <svg faIcon>-style directives as it's more generic and would solve a wider class of problems including the one you mention about unwanted wrapper element. It would require some thinking and design regarding fa-layers and friends and may not be trivial to implement using @fortawesome/fontawesome-svg-framework though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants