webcolor-labels: Plug-n-play #hex-syntax for your colors

[ graphics, library, mpl ] [ Propose Tags ] [ Report a vulnerability ]

This library contains a small number of helpers that primarily aim to help users construct IsLabel instances to use -XOverloadedLabels syntax to construct their color types using widely known web color syntax.

Plug this library into your code, enable OverloadedLabels and use #fff, #1212bc44, and even #fuchsia to create colors.


[Skip to Readme]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0
Change log CHANGELOG.md
Dependencies base (>=4.16.0.0 && <5.0.0.0) [details]
Tested with ghc ==9.8.4 || ==9.10.2 || ==9.12.2
License MPL-2.0
Author Andrei Borzenkov <me@sandwitch.dev>
Maintainer me@sandwitch.dev
Category Graphics
Home page https://github.com/haskell-game/webcolor-labels
Bug tracker https://github.com/haskell-game/webcolor-labels/issues
Source repo head: git clone https://github.com/haskell-game/webcolor-labels/
Uploaded by sandwitch at 2025-09-20T11:52:22Z
Distributions
Downloads 3 total (3 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for webcolor-labels-0.1.0.0

[back to package description]

webcolor-labels

Zero-dependency, plug-and-play library that enables #hex-color syntax for your own types!

Demo image

Motivation

Unrestricted OverloadedLabels syntax was implemented in GHC 9.6.1. It isn't hard to notice that this syntax is a strict superset of hexadecimal CSS color syntax, a.k.a. Web colors. It would be great if GUI libraries could take advantage of this fact and allow their users to write #f00 for the color "red," or even #red, right?

That's where webcolor-labels comes into play. This library implements type-level string parsing and validation and provides you an easy-to-use interface for defining an IsLabel instance. In fact, it's as easy as counting one, two, three:

-- one
import WebColor.Labels
import GHC.OverloadedLabels

-- two
instance IsWebColorAlpha s => IsLabel s YourColor where
  fromLabel = webColorAlpha @s yourColorFromWord8

-- three
yourColorFromWord8 :: Word8 -> Word8 -> Word8 -> Word8 -> YourColor
yourColorFromWord8 red green blue alpha = ...

And that's all!

Syntax

Allowed colors aim to follow the Wikipedia Web Colors page; here is a quick recap:

A color is written as a hex triplet, which is a six-digit (e.g., #fa12c7) or eight-digit (e.g., #fa12c7aa) hexadecimal number. The bytes represent the red, green, blue, and optional alpha channels of the color; hence we have #rrggbbaa.

It is possible to use the shorthand form with three and four digits: #f8c = #ff88cc and #f8c3 = #ff88cc33.

The syntax also supports 16 basic colors for convenience:

Color name Hex value
#white #FFFFFF
#silver #C0C0C0
#gray #808080
#black #000000
#red #FF0000
#maroon #800000
#yellow #FFFF00
#olive #808000
#lime #00FF00
#green #008000
#aqua #00FFFF
#teal #008080
#blue #0000FF
#navy #000080
#fuchsia #FF00FF
#purple #800080

Hex triplet form is case-insensitive; therefore, #fff is the same as #FFF, but basic colors are case-sensitive. That means #red is the same as #f00, but #RED and #Red result in a compile-time error.

FAQ

I want to use this syntax with $LIBRARYNAME, what should I do?

webcolor-label's primary users are other library authors; therefore, you should go to the $LIBRARYNAME's issue tracker and tell them that webcolor-labels will improve the lives of their users.

Alternatively, you may write an orphan instance, but it's a bad idea in general and you should avoid that as much as possible.

generic-lens uses the same syntax. Does that mean it will conflict with an instance defined using webcolor-labels?

No, unless you define a highly polymorphic IsLabel instance or your color is a type alias for a function.

The generic-lens instance applies only if a function is expected in place of #label. Therefore, define instances with a concrete head, and everything will work smoothly.

But what about instances for the color types from different libraries? Might they conflict?

No, if each instance is defined correctly.

I have a type class to represent colors. How can I use # syntax with a function that accepts my type class?

Unfortunately, my library just doesn't fit this use case. It's the same problem as show . read; GHC just can't infer a type in the middle.

I want to use different/custom values for named colors, but webcolor-labels provides pre-installed values. What should I do in that case?

You can still use type-level parsing from webcolor-labels and build custom routing on top of that, but you have to lower that into values yourself.

Contact info and acknowledgements

If you have any questions, you can email me using me@sandwitch.dev. Alternatively, you can DM me on Matrix (@root:sandwitch.dev) or Telegram (@sand_witch).

Many thanks to the Russian Haskell gamedev community, who encouraged me to convert this code into a real library and assisted with shaping the API.