atomic-css: Type-safe, composable CSS utility functions. Inspired by Tailwindcss and Elm-UI

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]

Type-safe, composable CSS utility functions. Inspired by Tailwindcss and Elm-UI . See documentation for the Web.Atomic module below


[Skip to Readme]

Properties

Versions 0.1.0, 0.1.0
Change log CHANGELOG.md
Dependencies base (>=4.16 && <5), bytestring (>=0.11 && <0.13), casing (>0.1.3.0 && <0.2), containers (>=0.6 && <1), effectful-core (>=2.3 && <3), file-embed (>=0.0.10 && <0.1), html-entities (>=1.1.4.7 && <1.2), http-types (>=0.12 && <0.13), text (>=1.2 && <3) [details]
License BSD-3-Clause
Author Sean Hess
Maintainer seanhess@gmail.com
Category Web
Home page https://github.com/seanhess/atomic-css
Bug tracker https://github.com/seanhess/atomic-css/issues
Source repo head: git clone https://github.com/seanhess/atomic-css
Uploaded by seanhess at 2025-05-21T16:10:27Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for atomic-css-0.1.0

[back to package description]

Atomic CSS

Hackage

Type-safe, composable CSS utility functions. Inspired by Tailwindcss and Elm-UI

Write Haskell instead of CSS

Style your html with composable CSS utility functions:

el ~ bold . pad 8 $ "Hello World"

This renders as the following HTML with embedded CSS utility classes:

<style type='text/css'>
.bold { font-weight:bold }
.p-8 { padding:0.500rem }
</style>

<div class='bold p-8'>Hello World</div>

Instead of relying on the fickle cascade, factor and compose styles with the full power of Haskell functions!

header = bold
h1 = header . fontSize 32
h2 = header . fontSize 24
page = flexCol . gap 10 . pad 10

example = el ~ page $ do
  el ~ h1 $ "My Page"
  el ~ h2 $ "Introduction"
  el "lorem ipsum..."

This approach is inspired by Tailwindcss' Utility Classes

Intuitive Flexbox Layouts

Create complex layouts with row, col, grow, and space

holygrail = do
  col ~ grow $ do
    row "Top Bar"
    row ~ grow $ do
      col "Left Sidebar"
      col ~ grow $ "Main Content"
      col "Right Sidebar"
    row "Bottom Bar"

Stateful Styles

We can apply utilities when certain states apply. For example, to change the background on hover:

button ~ bg Primary . hover (bg PrimaryLight) $ "Hover Me"

Media states allow us to create responsive designs

el ~ width 100 . media (MinWidth 800) (width 400) $ do
  "Big if window > 800"

Embedded CSS

Only the utilities used in a given html fragment are rendered:

>>> renderText $ el ~ bold $ "Hello"

<style type='text/css'>.bold { font-weight:bold }</style>
<div class='bold'>Hello</div>

Try Example Project with Nix

If you want to get a feel for atomic-css without cloning the project run nix run github:seanhess/atomic-css to run the example webserver locally

Import Flake

You can import this flake's overlay to add atomic-css to overriddenHaskellPackages and which provides a ghc966 and ghc982 package set that satisfy atomic-css's dependencies.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    atomic-css.url = "github:seanhess/atomic-css"; # or "path:/path/to/cloned/atomic-css";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, atomic-css, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ atomic-css.overlays.default ];
        };
        haskellPackagesOverride = pkgs.overriddenHaskellPackages.ghc966.override (old: {
          overrides = pkgs.lib.composeExtensions (old.overrides or (_: _: { })) (hfinal: hprev: {
            # your overrides here
          });
        });
      in
      {
        devShells.default = haskellPackagesOverride.shellFor {
          packages = p: [ p.atomic-css ];
        };
      }
    );
}

Local Development

If you want to work on both the atomic-css library and example code, this ghcid command will run and reload the examples server as you change any non-testing code.

ghcid --command="cabal repl exe:example lib:atomic-css" --run=Main.main --warnings --reload=./embed/preflight.css

If you want to work on the test suite, this will run the tests each time any library code is changed.

ghcid --command="cabal repl test lib:atomic-css" --run=Main.main --warnings --reload=./embed/preflight.css

Nix

Common Nix Issues

Not Allowed to Refer to GHC

If you get an error like:

error: output '/nix/store/64k8iw0ryz76qpijsnl9v87fb26v28z8-my-haskell-package-1.0.0.0' is not allowed to refer to the following paths:
         /nix/store/5q5s4a07gaz50h04zpfbda8xjs8wrnhg-ghc-9.6.3

Follow these instructions

Dependencies Incorrect

You will need to update the overlay, look for where it says "${packageName}" = hfinal.callCabal2nix packageName src { }; and add a line like Diff = hfinal.callHackage "Diff" "0.5" { }; with the package and version you need.

Missing Files

Check the include inside the nix-filter.lib to see if all files needed by cabal are there.

Learn More

View Documentation on Hackage

View on Github

View Examples

Contributors