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

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

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]

Properties

Versions 0.1.0.0, 0.1.0.0
Change log CHANGELOG.md
Dependencies base (>=4.16.0.0 && <5.0.0.0) [details]
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:48:39Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


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.