FluentCss 0.3.1

dotnet add package FluentCss --version 0.3.1
                    
NuGet\Install-Package FluentCss -Version 0.3.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FluentCss" Version="0.3.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FluentCss" Version="0.3.1" />
                    
Directory.Packages.props
<PackageReference Include="FluentCss" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FluentCss --version 0.3.1
                    
#r "nuget: FluentCss, 0.3.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FluentCss@0.3.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FluentCss&version=0.3.1
                    
Install as a Cake Addin
#tool nuget:?package=FluentCss&version=0.3.1
                    
Install as a Cake Tool

FluentCss

Utility-first CSS builder for .NET — generate Tailwind-inspired utility CSS classes on-the-fly from C# code.

⚠️ Pre-release software. FluentCss is in active development and has not reached a stable release. The public API — interface shapes, method names, generated class names and CSS output — may change between versions without a major-version bump. Pin an exact version and read the release notes before upgrading.


Using an AI coding agent? See the agent usage guide: AGENTS.md.

Overview

FluentCss lets you build CSS utility classes directly in .razor/.cshtml files using a fluent, chainable API. Instead of writing CSS by hand, you compose styles with type-safe method calls — and FluentCss automatically generates the CSS and class names.

  • Fluent builder API — chain methods like .Background(Color.Red500).Color(Color.White).P(4)
  • Full color palette — 22 color families (red, blue, green, slate, etc.), 11 shades each, plus black/white (taken from TailwindCss)
  • Pseudo-classes — Hover(...), Focus(...), Active(...), and custom Pseudo("...", ...)
  • Theming / dark mode — FluentCssBuilder.Dark or FluentCssBuilder.Theme("dark")
  • Responsive design — MinMd(...), MaxMd(...), and custom Media(...) queries
  • Automatic CSS output — classes are deduplicated and the final CSS is available as Css, build artifact or Razor component
  • Blazor/Razor integration — drop <CssStyles /> into your layout and get live CSS injection

Packages

Package Target Description
FluentCss.Core netstandard2.0 Core builder, registry, and all CSS utilities
FluentCss net10.0 Blazor component <CssStyles>, the MVC/Razor Pages tag helpers and the preflight stylesheet
FluentCss.Middleware net10.0 ASP.NET Core middleware and the AddFluentCss() / UseFluentCss() extensions

Installation

dotnet add package FluentCss             # For Blazor and MVC/Razor Pages tag helpers
dotnet add package FluentCss.Middleware  # For MVC/Razor Pages middleware

Nuget.org links: FluentCss, FluentCss.Middleware.

Quick Start

1. Blazor (Razor Components)

Add the following directives to your _Imports.razor for a cleaner syntax:

@using static FluentCss.Core.FluentCssBuilder
@using FluentCss.Core

Add <CssStyles /> ad preflight to your layout (e.g., App.razor or MainLayout.razor):

<link rel="stylesheet" href="_content/FluentCss/preflight.css" />
<CssStyles />

Preflight is licensed by Tailwind under MIT license.

Then build classes anywhere in your components using the shorthand @Css and @Dark:

<p class="
    @Css.Background(Color.Slate400).Color(Color.Green400)
        .Hover(h => h.Background(Color.Black).Color(Color.White))
    @Css.MinMd(md => md.Color(Color.Green800)
        .Hover(h => h.Color(Color.Gray400)))
    @Dark.Background(Color.Black).Color(Color.White)
        .Hover(h => h.Background(Color.Red300).Color(Color.Red800))">
    Hello, world!
</p>

The generated HTML class attribute will be something like:

bg-slate-400 text-green-400 hover:bg-black hover:text-white max-md:text-green-800 max-md:hover:text-gray-400 dark:bg-black dark:text-white dark:hover:bg-red-300 dark:hover:text-red-800

And FluentCss automatically emits the corresponding CSS into the page.

Alternativly you can place styles inside a class:

using FluentCss.Core;
using static FluentCss.Core.FluentCssBuilder;

public static class MyStyles
{
    public static string MyElement { get; } =
        $"""
         {Css.Background(Color.Slate400).Color(Color.Green400).Hover(h => h.Background(Color.Black).Color(Color.White))}
         {Css.MinMd(md => md.Color(Color.Green800).Hover(h => h.Color(Color.Gray400)))}
         {Dark.Background(Color.Black).Color(Color.White).Hover(h => h.Background(Color.Red300).Color(Color.Red800))}
         """;
}

and use it as

<p class="@MyStyles.MyElement">
    Test
</p>

⚠️ Important: The inline @Css.Chain().Method() syntax only works on HTML elements (<div>, <p>, <a>, etc.). Blazor components (<NavLink>, <InputText>, etc.) do not support complex C# expressions in their attributes. For component attributes, precompute the class string in a @code block or a static class (as shown above) and pass a simple variable:

@* ❌ Does NOT work on components *@
<NavLink class="@Css.Background(Color.Blue500).Color(Color.White)">...</NavLink>

@* ✅ Works on components *@
<NavLink class="@NavLinkClass">...</NavLink>

@code {
    private static string NavLinkClass = Css.Background(Color.Blue500).Color(Color.White).ToString();
}

Blazor without the component: A server-hosted Blazor app can also use the middleware and script-link path described in the next section. The tag helpers ship in the FluentCss package next to <CssStyles>; the middleware itself is in FluentCss.Middleware. The script path keeps the stylesheet in sync after client-side DOM changes, which suits Blazor Server and Blazor Web Apps.

2. ASP.NET Core MVC / Razor Pages

Add the FluentCss package for the tag helpers and FluentCss.Middleware for the middleware, then register it in Program.cs. It serves the current hash at /fluentcss/hash and the stylesheet at /fluentcss/{hash}.css, with gzip and an ETag:

builder.Services.AddFluentCss();

...

app.UseRouting();
app.UseFluentCss();   // serve /fluentcss/hash and /fluentcss/{hash}.css
app.UseAuthorization();

Register the tag helper and the namespaces in _ViewImports.cshtml (or Pages/_ViewImports.cshtml for Razor Pages):

@using static FluentCss.Core.FluentCssBuilder
@using FluentCss.Core
@addTagHelper *, FluentCss

Finally add the tag helper and, optionally, the Tailwind CSS reset (preflight) to your layout:

<head>
    ...
    <link rel="stylesheet" href="/_content/FluentCss/preflight.css" />
    <fluent-css />
</head>

The tag helper renders the stylesheet <link> and a small script that keeps it in sync after client-side DOM changes, such as a partial view loaded over AJAX.

3. Non-Blazor / Any .NET App

using FluentCss.Core;

// Create a root builder (registers classes in the default registry)
var classes = FluentCssBuilder.Css
    .Background(Color.Emerald500)
    .Color(Color.White)
    .Flex(FlexDirection.Row, Justify.Between, Align.Center)
    .Px(6).Py(3)
    .RoundedMd();

// Get the class string for your HTML
string classAttr = classes.ToString();
// => "bg-emerald-500 text-white flex flex-row justify-between items-center px-6 py-3 rounded-md"

// Get the auto-generated CSS
string css = ClassRegistry.DefaultRegistry.Css;

Builder API

Entry Points

FluentCssBuilder.Css         // standard builder
FluentCssBuilder.Dark        // dark theme builder (prefix: "dark:")
FluentCssBuilder.Theme(name) // custom theme builder (prefix: "theme-{name}:")

Layout

Method CSS
.Block() display: block
.InlineBlock() display: inline-block
.Inline() display: inline
.Flex() display: flex
.Grid() display: grid
.Hidden() display: none
.Relative() position: relative
.Absolute() position: absolute
.Fixed() position: fixed
.Sticky() position: sticky
.Inset(n) inset (n × 0.25rem)
.Top(n) / .Bottom(n) / .Left(n) / .Right(n) positional offsets
.Z(n) z-index

Flexbox

// Individual methods
.FlexRow()        .FlexCol()
.FlexWrap()       .ItemsCenter()     .ItemsStart()     .ItemsEnd()
.JustifyCenter()  .JustifyBetween()  .JustifyStart()   .JustifyEnd()
.Gap(n)           .GapX(n)           .GapY(n)
.Grow()           .Shrink()

// Composite method
.Flex(FlexDirection.Row, Justify.Center, Align.Center, gap: 4)

FlexDirection: Row, RowReverse, Col, ColReverse
Justify: Start, End, Center, Between, Around, Evenly
Align: Start, End, Center, Baseline, Stretch
FlexWrapValue: Wrap, NoWrap, WrapReverse

Grid

.GridCols(n)      .GridRows(n)
.ColSpan(n)       .RowSpan(n)
.ColStart(n)

Spacing

Spacing scale: n × 0.25rem. E.g., P(4) = 1rem.

Method CSS
.P(n) / .Px(n) / .Py(n) padding / padding-inline / padding-block
.Pt(n) / .Pr(n) / .Pb(n) / .Pl(n) directional padding
.M(n) / .Mx(n) / .My(n) margin / margin-inline / margin-block
.Mt(n) / .Mr(n) / .Mb(n) / .Ml(n) directional margin
.MxAuto() / .MyAuto() auto margins
.SpaceX(n) / .SpaceY(n) space between child elements
.DivideX(n) / .DivideY(n) / .DivideColor(Color) borders between child elements

Sizing

.W(n)       .WFull()    .WScreen()    .WAuto()
.WFit()     .WMin()     .WMax()
.H(n)       .HFull()    .HScreen()
.HFit()     .HMin()     .HMax()
.MaxW(Size.Md)    .MinW(Size.Sm)
.MaxH(Size.Lg)    .MinH(Size.Zero)

Predefined sizes: Size.Sm, Size.Md, Size.Lg, Size.Xl, Size.Xxl, Size.Xxxl, Size.Full, Size.ScreenH, Size.ScreenW, Size.Zero, Size.Min, Size.Max, Size.Fit.

Typography

.TextXs()    .TextSm()    .TextBase()
.TextLg()    .TextXl()    .Text2Xl()    .Text3Xl()
.Text4Xl()   .Text5Xl()   .Text6Xl()    .Text7Xl()   .Text8Xl()  .Text9Xl()
.FontThin()  .FontNormal()  .FontBold()
.TextCenter() .TextLeft() .TextRight() .TextEnd()
.Underline() .NoUnderline()
.Italic()    .NotItalic()
.Uppercase() .Lowercase() .Capitalize()
.Leading(n)  .WhitespaceNoWrap()
.DecorationColor(Color.Indigo500)  .Decoration(2)
.DecorationSolid()  .DecorationWavy()  .UnderlineOffset(4)
.AlignMiddle()  .AlignTop()  .AlignBaseline()

Colors

.Background(Color.Red500)    // background-color
.Color(Color.White)           // color
.BorderColor(Color.Slate200) // border-color

22 color families × 11 shades (50–950) + Black and White.
Examples: Color.Red50, Color.Blue700, Color.Emerald400, Color.Slate950.

Borders

.Border()           // 1px solid
.Border(2)          // 2px width
.Border(2, Color.Slate300, BorderStyle.Dashed)
.BorderSolid()  .BorderDashed()  .BorderDotted()
.Rounded()     .RoundedSm()   .RoundedMd()   .RoundedLg()   .RoundedFull()
.RoundedXl()   .Rounded2Xl()  .Rounded3Xl()
.RoundedT()    .RoundedR()    .RoundedB()    .RoundedL()    // two corners each
.RoundedTL()   .RoundedTR()   .RoundedBR()   .RoundedBL()   // one corner each
.Ring(2, Color.Blue200)        // ring (box-shadow based outline)
.Outline(2)    .OutlineHidden()  .OutlineSolid()  .OutlineDashed()

Effects & Utilities

.Shadow()   .ShadowMd()   .ShadowLg()
.Opacity(50)          // 0-100 → opacity: 0.5
.CursorPointer()
.OverflowAuto()  .OverflowHidden()  .OverflowScroll()
.OverflowXAuto() .OverflowYAuto()  .OverflowXHidden()  .OverflowYHidden()
.Container()     // full width + responsive max-widths
.ObjectCover()   .ObjectContain()
.AspectSquare()  .AspectVideo()

// Transitions
.Transition()  .TransitionColors()  .Duration(300)  .EaseInOut()

// Transforms (set transform directly; they do not compose)
.Rotate(45)  .Scale(50)  .TranslateX(4)  .OriginTop()  .TransformNone()

// Filters (set filter directly; they do not compose)
.Blur()  .Grayscale()  .Brightness(50)  .DropShadowLg()  .FilterNone()

Pseudo-classes

.Hover(h => h.Background(Color.Blue600))
.Focus(f => f.Ring(2, Color.Blue300))
.Active(a => a.Background(Color.Blue700))
.Pseudo("nth-child(2)", x => x.Background(Color.Gray100))

Pseudo-elements use the same shape and emit a double colon:

.Placeholder(p => p.Color(Color.Neutral400))  // ::placeholder
.Before(b => b.Background(Color.Red500))      // ::before
.After(a => a.Underline())                    // ::after
.Marker(m => m.Color(Color.Blue500))          // ::marker
.Selection(s => s.Background(Color.Blue200))  // ::selection
.File(f => f.RoundedMd())                     // ::file-selector-button

.Pseudo("part(label)", ...), Backdrop(...), FirstLetter(...) and FirstLine(...) cover the remaining pseudo-elements. Pseudo(...) decides between one and two colons from the name; a leading : / :: forces it.

Media Queries (responsive)

FluentCssBuilder.Css
    .Background(Color.Red500)
    .MinMd(m => m.Background(Color.Blue500))    // @media (width > 48rem)
    .MaxMd(m => m.Background(Color.Green500));  // @media (width < 48rem)

Custom media queries:

.Media("min-width: 1024px", "lg", builder =>
{
    builder.Flex(FlexDirection.Row);
    builder.P(8);
});

Theming / Dark Mode

// Use the dark theme entry point
string darkClasses = FluentCssBuilder.Dark
    .Background(Color.Slate800)
    .Color(Color.Slate100)
    .ToString();
// => "dark:bg-slate-800 dark:text-slate-100"

// Or inline theming
string themeClasses = FluentCssBuilder.Theme("halloween")
    .Background(Color.Orange500)
    .ToString();
// => "theme-halloween:bg-orange-500"

Getting the CSS Output

The ClassRegistry aggregates all utility classes and generates the final CSS:

string css = ClassRegistry.DefaultRegistry.Css;

In Blazor, the <CssStyles /> component subscribes to ClassRegistry.DefaultRegistry.OnClassAdded and automatically updates the rendered <style> block in real time. It also implements IDisposable to clean up the event subscription.

How It Works

  1. You call fluent builder methods (e.g., .Background(Color.Red500))
  2. Each call creates a UtilityClass instance (CSS property + value + generated class name)
  3. The class is added to a ClassRegistry — duplicates are ignored
  4. The registry builds a CSS string automatically
  5. .ToString() on the builder returns the space-separated class names for your class attribute

Class Name Format

[media-prefix]:[theme]:[pseudo]:{utility}

Examples:

  • bg-red-500 — plain utility
  • hover:bg-red-600 — hover pseudo
  • dark:text-white — dark theme
  • max-md:bg-black — responsive (max-md media prefix)
  • dark:hover:bg-slate-700 — combined theme + pseudo

License

BSD Zero Clause License (0BSD) — a public-domain-equivalent license with no restrictions.

Color values adapted stolen from Tailwind CSS (MIT licensed).

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.1 75 10/31/2026
0.3.0 66 10/31/2026
0.2.0 74 10/31/2026
0.1.0 82 10/30/2026