Skip to content
Citia DS

Getting started

Installation

Add the Citia.DesignSystem NuGet package to an ASP.NET Core app, wire the layout, and choose precompiled CSS or your own Tailwind build.

Installing has four parts: add the package, import its tag helpers, put four partials in the layout, and choose how the CSS reaches the browser. Razor, JavaScript, fonts and icons are the same for both CSS options.

1. Add the package

The library is the NuGet package Citia.DesignSystem on the Citia feed. Put a nuget.config next to your solution file:

XML
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="citia" value="https://design.citia-engineering.com/nuget/v3/index.json" />
  </packageSources>
  <packageSourceMapping>
    <packageSource key="nuget.org"><package pattern="*" /></packageSource>
    <packageSource key="citia"><package pattern="Citia.*" /></packageSource>
  </packageSourceMapping>
</configuration>

Commit it. Every developer and every build server then restores the same way, with no token and no setup on their machine. The mapping takes Citia.* packages only from the Citia feed and everything else only from nuget.org. If your repository already has a nuget.config, add the citia source and its mapping to it.

Then, in the web project folder:

PowerShell
dotnet add package Citia.DesignSystem

This writes the latest stable version into the .csproj. The static assets (ds.css, ds.js, fonts, icons, tokens) are then served from /_content/Citia.DesignSystem/, and the CSS sources ship inside the package under styles/. To update later, see Releases and updates.

Note

Working on the design system itself? Reference the project instead, with the DS repository next to your app: dotnet add reference ..\..\citia-design-system\src\Citia.DesignSystem\Citia.DesignSystem.csproj. Switch back to the package before you commit app code.

2. Program.cs

C#
using System.Globalization;
using Microsoft.AspNetCore.Localization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();          // or AddControllersWithViews()
builder.Services.AddSession();             // only if you keep TempData in session; cookie TempData needs nothing

var app = builder.Build();

// English and Indonesian. The request culture drives DsText (server strings), Fmt (dates, numbers) and <html lang>.
string[] languages = ["en", "id"];
app.UseRequestLocalization(new RequestLocalizationOptions()
    .SetDefaultCulture("en")
    .AddSupportedCultures(languages)
    .AddSupportedUICultures(languages));

app.UseStaticFiles();                      // development: serves RCL assets without a build
app.UseRouting();
app.MapStaticAssets();                     // .NET 9+: fingerprinted, compressed static assets
app.MapRazorPages().WithStaticAssets();
app.Run();

UseRequestLocalization reads the query string ?culture=id, a culture cookie, then Accept-Language. To switch language from a link, write the cookie:

C#
app.MapPost("/language", (HttpContext http, string culture, string returnUrl) =>
{
    http.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1), SameSite = SameSiteMode.Lax });
    return Results.LocalRedirect(returnUrl);
});

Add another language for server strings with DsText.Add("ms", new Dictionary<string, string> { ["pager.next"] = "Seterusnya" }) at startup, and for browser strings with DS.addMessages.

3. _ViewImports

Pages/_ViewImports.cshtml (Razor Pages) or Views/_ViewImports.cshtml (MVC):

Razor (.cshtml)
@using Citia.DesignSystem.Icons
@using Citia.DesignSystem.Ui
@using Citia.DesignSystem.Formatting
@using Citia.DesignSystem.Localization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Citia.DesignSystem

4. Layout

Razor (.cshtml)
@using System.Globalization
<!DOCTYPE html>
<html lang="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName" data-theme="light">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>@ViewData["Title"] - My App</title>
    @* Before every other stylesheet: it sets the theme before first paint, so dark mode never flashes light. *@
    <partial name="_DsHead" />
</head>
<body>
    <partial name="_DsIconSprite" />
    <a class="ds-skip-link btn btn-primary btn-sm" href="#main">@DsText.T("skip")</a>

    <main id="main">@RenderBody()</main>

    <partial name="_DsToast" />
    <partial name="_DsScripts" />
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Partial Place Does
_DsHead <head>, before other CSS Colour-scheme and theme-colour meta, font preload, theme bootstrap script, stylesheet.
_DsIconSprite Start of <body> Inline SVG sprite used by <ds-icon>. Once per page.
_DsToast End of <body> Live region and the toast queued with this.Toast(...) before a redirect.
_DsScripts End of <body> Loads ds.js as an ES module. Deferred by nature.

Add _DsConfirmDialog and _DsLeaveDialog when you use confirm dialogs and unsaved-change guards. For a sidebar and top bar see Page patterns.

Language and theme

  • Language. The server writes <html lang> from the request culture. ds.js reads that attribute for its own strings, so server and browser stay in step. To override, call DS.configure({ locale: "id" }) before init.
  • Theme. The server default is data-theme="light". _DsHead then applies the saved choice, or the system preference, before first paint. Options go through HeadOptions:
Razor (.cshtml)
<partial name="_DsHead" model='new HeadOptions(Light: "light", Dark: "dark", Storage: "myapp")' />

Storage is the localStorage key prefix (myapp-theme); give each app on the same domain its own. Add data-ds-theme-set="light|dark|system" buttons or the theme switcher to let people choose. See Theming.

5. Get the CSS to the browser

Option A: precompiled ds.css

No Tailwind, no build step. _DsHead with no model already links /_content/Citia.DesignSystem/css/ds.css, which contains the Tailwind preflight, daisyUI 5, the tokens and every ds-* component.

Razor (.cshtml)
<partial name="_DsHead" />

It contains no Tailwind utilities (flex, gap-2, p-4). Write your own layout CSS with plain rules and token variables such as var(--ds-space-4) and var(--color-base-100), or use the layout components. Choose this for small apps, internal tools and prototypes.

Option B: your own Tailwind build

Use this when you want Tailwind utilities in your views. The DS imports into your input CSS, so your build produces one file.

Styles/app.css:

CSS
@import "tailwindcss" source(none);
@plugin "../../../citia-design-system/.tools/daisyui.mjs" {
  themes: false;
  logs: false;
}
@import "../../../citia-design-system/src/Citia.DesignSystem/Styles/ds.css";

/* Classes used by your views and by the DS partials */
@source "../Views";
@source "../Pages";
@source "../wwwroot/js";
@source "../../../citia-design-system/src/Citia.DesignSystem/Views";

/* App-specific CSS below */

themes: false matters: the DS tokens define every daisyUI variable per data-theme, so daisyUI's own themes stay off. With the NuGet package, the CSS sources travel inside it under styles/; point the import there.

Run the DS script once to download the pinned, SHA-256 verified Tailwind CLI and daisyui.mjs into .tools/:

PowerShell
cd D:\work\citia-design-system
powershell -NoProfile -File tools/css.ps1

Then build your CSS, by hand or as an MSBuild step:

XML
<PropertyGroup>
  <CitiaDs>$(MSBuildProjectDirectory)\..\..\citia-design-system</CitiaDs>
</PropertyGroup>
<Target Name="BuildCss" BeforeTargets="BeforeBuild"
        Condition="$([MSBuild]::IsOSPlatform('Windows')) And Exists('$(CitiaDs)\.tools\tailwindcss.exe')">
  <Exec Command="&quot;$(CitiaDs)\.tools\tailwindcss.exe&quot; -i Styles\app.css -o wwwroot\css\app.css --minify" />
</Target>

Watch mode while you design: tailwindcss.exe -i Styles\app.css -o wwwroot\css\app.css --watch. Point the head partial at your output:

Razor (.cshtml)
<partial name="_DsHead" model='new HeadOptions(Stylesheet: "~/css/app.css")' />

Important

wwwroot/css/app.css is build output. Add it to .gitignore and rebuild after every git pull.

Check the installation

  • <html> has data-theme, data-ds-mode and data-ds-scheme after load.
  • ds.js, the stylesheet and the Manrope font return 200 in the Network tab.
  • A [data-ds-theme-set] button changes the theme and the choice survives a reload.
  • ?culture=id switches <html lang> and server strings to Indonesian.
  • Press Tab first thing on a page: the skip link appears and every control shows a focus ring.
  • this.Toast(...) followed by a redirect shows a toast.

Common problems

Symptom Cause Fix
Can't resolve 'daisyui' while building CSS Wrong @plugin path, or .tools not downloaded Run tools/css.ps1; check the relative path from Styles/app.css.
Tailwind utilities missing View folder not listed in @source Add an @source line for it.
Light flash on dark pages _DsHead placed after another stylesheet Put it first in <head>.
Icons are empty Sprite not rendered Add _DsIconSprite once per page.
Toast does not appear _DsToast missing, or no redirect after Toast() Add the partial and use Post/Redirect/Get.
Font 404 under a sub-path Font URLs are absolute (/_content/...) Serve the app at a domain root, or copy the fonts and use Styles/fonts.root.css.
dotnet rejects net10.0 SDK 10 not installed See Requirements.
NU1101: Unable to find package Citia.DesignSystem No citia source in a nuget.config that applies to the project Put the nuget.config from step 1 next to the solution or in a parent folder.

Next: build a page with the quick start.

Citia Design System 2.0.1 · Citia Engineering Indonesia. Derived from INTEGRA TPS Integration; built for every Citia web application.