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

[ bsd3, library, web ] [ Propose Tags ] [ Report a vulnerability ]
Versions [RSS] 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]
Tested with ghc ==9.8.2, ghc ==9.6.6
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:15:47Z
Distributions
Downloads 0 total (0 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 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

  • nix flake check will build the library, example executable and devShell with ghc-9.8.2 and ghc-9.6.6
    • This is what the CI on GitHub runs
  • nix run or nix run .#ghc982-example to start the example project with GHC 9.8.2
    • nix run .#ghc966-example to start the example project with GHC 9.6.6
  • nix develop or nix develop .#ghc982-shell to get a shell with all dependencies installed for GHC 9.8.2.
    • nix develop .#ghc966-shell to get a shell with all dependencies installed for GHC 9.6.6.
  • nix build, nix build .#ghc982-atomic-css and nix build .#ghc966-atomic-css builds the library with the overriddenHaskellPackages
    • If you want to import this flake, use the overlay
  • nix flake update nixpkgs will update the Haskell package sets and development tools

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