Configure Custom Styling
This guide shows you how to customize the visual appearance of your MyLittleContentEngine site using MonorailCSS.
MonorailCSS is a TailwindCSS compatible utility-first CSS framework that aims for syntax
compatibility with Tailwind
while providing enhanced customization capabilities. You'll learn to modify color palettes, implement theme switching,
and override default styling. It isn't required for MyLittleContentEngine, but the MyLittleContentEngine.UI package
makes assumptions that it's configured, or at least TailwindCSS is configured compatibly.
Note
Prerequisites
Before customizing styling, ensure you have MonorailCSS configured in your application:
dotnet add package MyLittleContentEngine.MonorailCss
Then register the MonorailCSS services in your Program.cs file:
// Program.cs
builder.Services.AddMonorailCss();
// rest of services configuration
var app = builder.Build();
app.UseMonorailCss();
MonorailCSS Services
MonorailCSS registers several services in the dependency injection container:
builder.Services.AddMonorailCss();
MonorailCssService- Core service that generates CSS stylesheets from collected classesCssClassCollector- Thread-safe service that maintains a collection of CSS classes found in HTML responses
These services work together to provide automatic CSS class discovery, color generation, and stylesheet compilation.
MonorailCSS Middleware
The CssClassCollectorMiddleware automatically scans HTML responses to discover CSS classes being used:
// Middleware is registered automatically when you call UseMonorailCss()
app.UseMonorailCss();
The middleware:
- Intercepts HTML responses using a regex pattern to find
class="..."attributes - Extracts individual CSS classes from the class attribute values
- Stores discovered classes in the
CssClassCollectorfor CSS generation
This automatic discovery ensures that only the CSS classes actually used in your application are included in the generated stylesheet.
Style.css Generation
MonorailCSS generates a complete CSS stylesheet at runtime through the /styles.css endpoint:
- Class Collection: The middleware collects CSS classes from rendered HTML
- Color Generation: Color palettes are generated from your configured hue values using OKLCH color space
- Component Styles: Built-in styles for code blocks, tabs, alerts, and other content engine components
- CSS Compilation: The
MonorailCssServicecombines all elements into a complete stylesheet
The generated CSS includes:
- Utility classes for discovered CSS classes (spacing, colors, typography, etc.)
- Component styles for syntax highlighting, tabbed code blocks, and markdown alerts
- Dark mode variants using the
dark:prefix - Custom styles defined in your
MonorailCssOptions.CustomCssFrameworkSettings
For static site generation, the CSS endpoint is automatically processed last to ensure all CSS classes have been discovered before generating the final stylesheet.
Understanding MonorailCSS Colors
MonorailCSS uses a TailwindCSS-compatible color system with numbered scales (50-950) and semantic color names. The framework generates a complete color palette from a primary hue, base colors, and automatically calculated accent and tertiary colors.
Color Scale Structure
Like TailwindCSS, MonorailCSS uses a numerical color scale:
50- Lightest shade100-400- Light shades500- Base/medium shade600-800- Dark shades900-950- Darkest shades
Customizing Color Palettes
MonorailCSS provides two approaches for defining color schemes: named color palettes (using predefined Tailwind colors) or algorithmic generation (generating palettes from hue values).
Named Color Scheme
The simplest approach uses named Tailwind colors for all five color roles:
builder.Services.AddMonorailCss(_ => new MonorailCssOptions
{
ColorScheme = new NamedColorScheme
{
PrimaryColorName = ColorNames.Blue, // Main theme color
AccentColorName = ColorNames.Purple, // Complementary accent
TertiaryOneColorName = ColorNames.Cyan, // Syntax highlighting
TertiaryTwoColorName = ColorNames.Pink, // Syntax highlighting
BaseColorName = ColorNames.Slate // Neutral colors
}
});
Algorithmic Color Scheme
For more control, generate palettes from hue values (0-360 degrees):
builder.Services.AddMonorailCss(_ => new MonorailCssOptions
{
ColorScheme = new AlgorithmicColorScheme
{
PrimaryHue = 230, // Blue-ish hue
BaseColorName = ColorNames.Zinc, // Base neutral palette
ColorSchemeGenerator = primary => ( // Optional customization
primary + 180, // Accent hue (complementary)
primary + 90, // Tertiary one hue
primary - 90 // Tertiary two hue
)
}
});
Available Color Names
MonorailCSS supports all TailwindCSS-compatible color names:
- Neutrals:
Gray,Slate,Zinc,Neutral,Stone - Colors:
Red,Orange,Amber,Yellow,Lime,Green,Emerald,Teal,Cyan,Sky,Blue,Indigo,Violet,Purple,Fuchsia,Pink,Rose
All colors defined by Tailwind CSS as of version 4.0 are available.
Generated Color Palettes
When you configure a primary hue, MonorailCSS automatically generates:
- primary-{50-950} - Your brand's primary color scale
- base-{50-950} - Neutral colors for backgrounds, text, borders
- accent-{50-950} - Complementary colors for highlights
- tertiary-one-{50-950} - Additional accent colors
- tertiary-two-{50-950} - Additional accent colors
All colors follow TailwindCSS naming conventions, so you can use them like:
<div class="bg-primary-600 text-primary-50 border-primary-700">
<p class="text-base-800 dark:text-base-200">
<button class="bg-accent-500 hover:bg-accent-600">
All colors supported by TailwindCSS are available, but it's recommended to stick to base, primary, and accent
for your primary design system colors, as these are the ones that'll be used by the MonorailCSS components.
Implementing Dark/Light Theme Switching
MyLittleContentEngine includes built-in theme switching functionality that requires specific HTML markup and JavaScript integration.
HTML Markup
Add a theme toggle button with the data-theme-toggle attribute:
<button aria-label="Toggle Dark Mode" data-theme-toggle>
<!-- Sun icon for light mode -->
<svg class="dark:hidden" viewBox="0 0 24 24">
<!-- sun icon path -->
</svg>
<!-- Moon icon for dark mode -->
<svg class="hidden dark:block" viewBox="0 0 24 24">
<!-- moon icon path -->
</svg>
</button>
JavaScript Integration
The theme switching is handled automatically by the included JavaScript. The ThemeManager class:
- Finds theme toggle buttons - Searches for elements with
[data-theme-toggle] - Binds click events - Automatically wires up the theme switching functionality
- Manages theme state - Toggles the
darkclass ondocument.documentElement - Persists preference - Saves theme choice to
localStorage
Dark Mode with TailwindCSS Syntax
MonorailCSS supports TailwindCSS dark mode syntax using the dark: prefix:
<!-- TailwindCSS-compatible dark mode classes -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<p class="text-primary-700 dark:text-primary-300">
<button class="bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-400">
Setting the Default Dark/Light Theme
By default, your pages will display in light mode unless you've set the dark class on the <html> element.
You can make this more dynamic by adding a small script in the <head> section of your HTML to check the user's
preference:
<script>
// this is actually duplicated in scripts.js, but we need it here to ensure the
// theme is set before the page loads to avoid flash of unstyled content
const isDarkMode = localStorage.theme === "dark" || (!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches);
document.documentElement.classList.toggle("dark", isDarkMode);
document.documentElement.dataset.theme = isDarkMode ? "dark" : "light";
</script>
This script checks the user's preference and applies the dark theme if they've set it
or if their system preference is for dark mode. You don't want to do this in the scripts.js file,
as it won't be executed until the page has loaded, which will cause a flash of unstyled content (FOUC).
Instead, you can place this script in the <head> section of your HTML to ensure it runs before the page is rendered.
Custom CSS Framework Settings
You can override MonorailCSS defaults to customize fonts, typography, and other design system elements:
Custom Fonts
builder.Services.AddMonorailCss(_ => new MonorailCssOptions
{
CustomCssFrameworkSettings = defaultSettings => defaultSettings with
{
DesignSystem = defaultSettings.DesignSystem with
{
FontFamilies = defaultSettings.DesignSystem.FontFamilies
.Add("display", new FontFamilyDefinition("Lexend, sans-serif"))
.SetItem("mono", new FontFamilyDefinition("""
"Cascadia Code", ui-monospace, SFMono-Regular,
Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace
"""))
}
}
});
Custom CSS Classes with TailwindCSS Utilities
You can add custom CSS rules using TailwindCSS-compatible utility classes:
CustomCssFrameworkSettings = defaultSettings => defaultSettings with
{
Applies = new Dictionary<string, string>
{
// Custom component styles using TailwindCSS syntax
{ ".my-custom-card", "bg-base-100 border border-base-300 rounded-lg p-4 shadow-sm dark:bg-base-900 dark:border-base-700" },
// Button variants
{ ".btn-primary", "bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-md transition-colors dark:bg-primary-500 dark:hover:bg-primary-400" },
// Override existing styles
{ ".prose code", "bg-primary-100 text-primary-800 px-2 py-1 rounded dark:bg-primary-900 dark:text-primary-200" }
}
}
The Applies dictionary lets you define reusable component classes using the full range of TailwindCSS utilities that
MonorailCSS supports. This is especially useful when integrating with JavaScript frameworks. These apply elements are
used, for example, to style the syntax highlighting in the code blocks.
Complete Example
Here's a complete example showing advanced styling customization:
// Program.cs
builder.Services.AddMonorailCss(_ => new MonorailCssOptions
{
// Custom brand colors using algorithmic generation
ColorScheme = new AlgorithmicColorScheme
{
PrimaryHue = 205, // Brand blue
BaseColorName = ColorNames.Slate,
ColorSchemeGenerator = primary => (
primary + 155, // Green accent
primary + 45, // Purple tertiary
primary - 30 // Orange tertiary
)
},
// Advanced framework customization
CustomCssFrameworkSettings = defaultSettings => defaultSettings with
{
DesignSystem = defaultSettings.DesignSystem with
{
// Custom fonts
FontFamilies = defaultSettings.DesignSystem.FontFamilies
.Add("brand", new FontFamilyDefinition("Inter, sans-serif"))
.SetItem("mono", new FontFamilyDefinition("'JetBrains Mono', monospace"))
},
// Custom component styles using TailwindCSS utilities
Applies = new Dictionary<string, string>
{
{ ".hero-section", "bg-gradient-to-br from-primary-50 to-accent-100 dark:from-primary-950 dark:to-accent-900" },
{ ".card-elevated", "bg-base-50 shadow-lg border border-base-200 rounded-xl p-6 dark:bg-base-900 dark:border-base-700" },
{ ".btn-outline", "border-2 border-primary-500 text-primary-600 hover:bg-primary-500 hover:text-white transition-colors px-4 py-2 rounded-lg" }
}
}
});
Troubleshooting
No Styling Applied: Ensure you're using the LinkService for resolving the CSS file properly
@inject LinkService LinkService // ... <link rel="stylesheet" href="@LinkService.GetLink("styles.css")" />Theme not switching: Ensure your button has the
data-theme-toggleattribute and the JavaScript is loaded.