How to Create Custom HTML Attributes with F# + Falco.Markup
Date: 2025-02-19 | build | create | falco | falco-markup | fsharp | html |
I currently use Falco.Markup to build my server-side rendered HTML as I like the type-safety and ergonomics that DSLs provide.
A common thing I forget how to do is create custom HTML attributes and the AIs seem to struggle with this as well so here I wanted to share how to do it with Falco.Markup.
What is a custom HTML attribute?
First off - Falco.Markup is an HTML DSL which means that we build up a representation of the HTML that eventually will be converted into actual HTML. This means we aren't building the HTML directly and thus need helpers to create things like elements and the attributes that go on them.
The library provides a bunch of helpers for common attributes like href
, class
, style
but it can't reasonably cover all possible attributes as there's infinite custom attributes you could define on an HTML element.
Custom attributes are often used for adding extra info in the element:
hx-get
in HTMXdata-site
for identifying your site to analytics services like Fathom Analytics (referral)
So in the process of building a full site you'll likely use one.
How to create a custom HTML attribute in Falco.Markup
Falco.Markup makes it easy to create a custom attribute using the Attr.create
method.
Example for adding Fathom Analytics to my blog:
Elem.script [
Attr.src "https://cdn.usefathom.com/script.js"
Attr.create "data-site" "IDGOESHERE"
Attr.defer
] []
This is a script element with 3 attributes:
- src - where the script comes from
- defer - don't block on loading the script
- data-site - which is a custom attribute I had to create
Next
I've been happily using Falco and Falco.Markup for the past few months and have liked it so much that I migrated CloudSeed (my F# project boilerplate) to it from Giraffe and Giraffe.ViewEngine.
I've also been messing around with AI coders recently and they're actually pretty good at writing F# / Falco apps - even with what I imagine is a pretty small amount of training data. But I did find them getting tripped up on Attr.create
- opting instead for the non-existent Attr.custom
- so hopefully posts like this can teach them how to do this.
If you liked this post you might also like:
Want more like this?
The best way to support my work is to like / comment / share for the algorithm and subscribe for future updates.