Tailwind classes in OCaml
OCaml 96.3%
Dune 0.3%
CSS 0.1%
Other 3.4%
18 1 0

Clone this repository

https://tangled.org/anil.recoil.org/ocaml-tailwind
git@git.recoil.org:anil.recoil.org/ocaml-tailwind

For self-hosted knots, clone URLs may differ based on your setup.

README.md

Tailwind OCaml#

Type-safe Tailwind CSS generation for OCaml with a revolutionary GADT-based interface for succinct, compile-time validated styling.

This project provides two main libraries:

  • tailwind: Core library for type-safe Tailwind CSS class generation
  • tailwind-html: High-level HTML component library with GADT-based heterogeneous list interface built on Htmlit

Features#

  • GADT-based Interface: Succinct heterogeneous list syntax with compile-time type safety
  • Zero Runtime Cost: All CSS generation happens at compile time
  • Comprehensive Grid Support: Full CSS Grid integration with type-safe properties
  • Type-Safe Colors & Spacing: Exhaustive variants with compile-time validation
  • Built-in Components: Pre-styled buttons, cards, and layout helpers

Complete Tailwind Coverage#

  • Typography: Font sizes, weights, text alignment with type-safe variants
  • Layout: CSS Grid, Flexbox, spacing with compile-time validation
  • Colors: Full palette (gray, blue, red, green, etc.) with variant checking
  • Effects: Shadows, borders, rounded corners, transitions
  • Components: Pre-built buttons, cards, and layout helpers
  • Type Safety: GADT-based heterogeneous lists prevent invalid combinations

Quick Start#

The new GADT-based interface provides succinct, type-safe styling with heterogeneous lists:

open Htmlit
open Tailwind_html

(* Create a centered card with CSS Grid *)
let create_hero_section () =
  div ~styles:[
    grid;
    grid_cols 1;
    gap (rem 2.0);
    padding (rem 3.0);
    text_center;
  ] [
    h1 ~styles:[
      font_size `Xl3;
      font_weight `Bold;
      text_color (blue 600);
      margin_bottom (rem 1.5);
    ] [txt "Welcome to Tailwind OCaml"];
    
    p ~styles:[
      font_size `Lg;
      text_color (gray 600);
      margin_bottom (rem 2.0);
    ] [txt "Type-safe CSS with compile-time guarantees"];
    
    (* Built-in button components *)
    btn_primary ~size:`Lg [txt "Get Started"];
  ]

CSS Grid Layouts#

(* Three-column responsive grid *)
div ~styles:[
  grid;
  grid_cols 3;
  gap (rem 1.5);
] [
  card [h3 [txt "Feature 1"]; p [txt "Description"]];
  card [h3 [txt "Feature 2"]; p [txt "Description"]];
  card [h3 [txt "Feature 3"]; p [txt "Description"]];
]

Built-in Components#

(* Pre-styled components with size variants *)
btn_primary ~size:`Lg [txt "Primary Action"];
btn_secondary [txt "Secondary Action"];
btn_outline ~size:`Sm [txt "Outline Button"];

(* Layout helpers *)
container [
  card [
    h2 ~styles:[font_size `Xl; margin_bottom (rem 1.0)] [txt "Card Title"];
    p ~styles:[text_color (gray 600)] [txt "Card content with automatic styling"];
  ];
]

Examples#

The examples/ directory showcases the GADT interface across various use cases:

Available Examples#

# Build all examples
dune build examples/

# Hello World with GADT interface
dune exec examples/hello_tailwind_01.exe > hello.html

# Colors and Typography showcase
dune exec examples/colors_and_typography_02.exe > colors.html

# CSS Grid and Layout demonstrations
dune exec examples/layout_and_spacing_03.exe > layout.html

# Responsive design patterns  
dune exec examples/responsive_design_04.exe > responsive.html

# Visual effects and styling
dune exec examples/effects_and_variants_05.exe > effects.html

# Component patterns and reusable elements
dune exec examples/patterns_and_components_06.exe > patterns.html

# Complete application showcase
dune exec examples/comprehensive_showcase_07.exe > showcase.html

# Button component demonstration
dune exec examples/button_demo.exe > buttons.html

# Generate index page linking all examples
dune exec examples/index_html_generator.exe > index.html

Example Highlights#

CSS Grid Layout (layout_and_spacing_03.ml):

(* Three-column grid with gap variations *)
div ~styles:[
  grid;
  grid_cols 3;
  gap (rem 1.0);
] [
  div ~styles:[bg_color (blue 100); padding (rem 1.0)] [txt "Item 1"];
  div ~styles:[bg_color (green 100); padding (rem 1.0)] [txt "Item 2"];
  div ~styles:[bg_color (purple 100); padding (rem 1.0)] [txt "Item 3"];
]

(* Asymmetric grid gaps *)
div ~styles:[
  grid;
  grid_cols 2;
  gap_x (rem 2.0);
  gap_y (rem 0.5);
] (List.init 4 (fun i ->
  div ~styles:[bg_color (purple 200); text_center] [
    txt (Printf.sprintf "Box %d" (i + 1))
  ]
))

Built-in Components (button_demo.ml):

(* Size variants with consistent styling *)
div ~styles:[flex; flex_col; gap (rem 1.0)] [
  btn_primary ~size:`Sm [txt "Small Primary"];
  btn_primary [txt "Default Primary"];
  btn_primary ~size:`Lg [txt "Large Primary"];
  btn_secondary [txt "Secondary Button"];
  btn_outline [txt "Outline Button"];
]

Responsive Cards (comprehensive_showcase_07.ml):

section ~styles:[margin_bottom (rem 4.0)] [
  h3 ~styles:[font_size `Xl2; text_center; margin_bottom (rem 3.0)] [
    txt "Features"
  ];
  
  div ~styles:[grid; grid_cols 1; gap (rem 2.0)] [
    card [
      h4 ~styles:[font_size `Xl; font_weight `Semibold; text_color (blue 600)] [
        txt "🎯 Type Safety"
      ];
      p ~styles:[text_color (gray 600)] [
        txt "Catch styling errors at compile time with GADT-based type checking."
      ];
    ];
    card [
      h4 ~styles:[font_size `Xl; font_weight `Semibold; text_color (green 600)] [
        txt "⚡ Performance" 
      ];
      p ~styles:[text_color (gray 600)] [
        txt "Zero runtime overhead with compile-time CSS generation."
      ];
    ];
  ];
]

Tailwind v4 Support#

This library supports Tailwind v4's CSS-first approach:

/* Generated input.css - no config file needed! */
@import "tailwindcss";

@theme {
  --font-sans: 'Inter', system-ui, sans-serif;
  --color-brand-600: #2563eb;
  /* Custom theme extensions */
}

To process the CSS:

npx tailwindcss@next -i input.css -o output.css

API Reference#

Tailwind_html (GADT Interface)#

The high-level GADT interface provides succinct, type-safe styling with heterogeneous lists:

Layout Properties#

~styles:[
  (* Display *)
  grid | flex | block | inline | hidden;
  
  (* Grid System *)
  grid_cols 3 | grid_rows 2;
  gap (rem 1.0) | gap_x (rem 1.5) | gap_y (rem 0.5);
  
  (* Flexbox *)
  flex_col | flex_row;
  justify_center | justify_between | justify_end;
  items_center | items_start | items_end;
  
  (* Sizing *)
  width full | height screen;
  min_height screen | max_width (rem 64.0);
]

Typography Properties#

~styles:[
  (* Font Sizes *)
  font_size `Xs | font_size `Sm | font_size `Base | font_size `Lg;
  font_size `Xl | font_size `Xl2 | font_size `Xl3;
  
  (* Font Weights *)
  font_weight `Light | font_weight `Normal | font_weight `Medium;
  font_weight `Semibold | font_weight `Bold;
  
  (* Text Styling *)
  text_center | text_left | text_right;
  text_color (blue 600) | text_color (gray 500);
]

Color System#

~styles:[
  (* Background Colors *)
  bg_color (blue 50) | bg_color (gray 100) | bg_color (red 500);
  bg_color (Tailwind.Color.white) | bg_color (green 600);
  
  (* Text Colors *)
  text_color (gray 800) | text_color (blue 600) | text_color (red 500);
  
  (* Border Colors *)
  border_color (gray 200) | border_color (blue 300);
]

Spacing Properties#

~styles:[
  (* Padding *)
  padding (rem 1.0) | padding_x (rem 1.5) | padding_y (rem 2.0);
  
  (* Margin *)
  margin (rem 1.0) | margin_x auto | margin_bottom (rem 2.0);
  margin_top (rem 1.5) | margin_left (rem 0.5);
]

Visual Effects#

~styles:[
  (* Shadows *)
  shadow `Sm | shadow `Md | shadow `Lg | shadow `Xl;
  
  (* Borders *)
  border | rounded `Sm | rounded `Md | rounded `Lg | rounded `Full;
  
  (* Transitions *)
  transition;
]

Built-in Components#

(* Button Components *)
btn_primary ~size:`Lg [txt "Primary Button"];
btn_secondary ~size:`Sm [txt "Secondary Button"];  
btn_outline [txt "Outline Button"];

(* Layout Components *)
container [content];     (* Max-width container with auto margins *)
card [content];         (* Pre-styled card with padding and shadow *)

(* HTML Elements with Styling *)
h1 ~styles:[font_size `Xl3; font_weight `Bold] [txt "Heading"];
p ~styles:[text_color (gray 600); margin_bottom (rem 1.0)] [txt "Paragraph"];
div ~styles:[grid; grid_cols 2; gap (rem 1.0)] [content];
section ~styles:[margin_bottom (rem 2.0)] [content];

Low-Level Tailwind Module#

For advanced use cases, the core Tailwind module provides detailed control:

open Tailwind

let classes = Css.tw [
  Display.grid;
  Grid.(to_class (template_cols (`Cols 3)));
  Spacing.(to_class (gap `All (Size.rem 1.0)));
  Color.bg (Color.make `Blue ~variant:`V50 ());
]

let html_class = to_string classes  (* "grid grid-cols-3 gap-4 bg-blue-50" *)

Getting Started#

Add to your dune-project:

(package
 (name myproject)
 (depends
  ocaml
  dune
  tailwind
  tailwind-html
  htmlit))

Then in your OCaml code:

open Htmlit
open Tailwind_html

let my_page = El.html [
  El.head [El.title [txt "My App"]];
  El.body ~at:[classes_attr [min_height screen; bg_color (gray 50)]] [
    container [
      h1 ~styles:[font_size `Xl3; text_center; margin_bottom (rem 2.0)] [
        txt "Welcome to Type-Safe CSS!"
      ];
      btn_primary [txt "Get Started"];
    ];
  ];
]

Testing#

Run the test suite:

dune test

Contributing#

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Submit a pull request

License#

MIT License - see LICENSE file for details

Acknowledgments#

Resources#