What Styling Solution Is Used in Securo Frontend?

Securo's frontend uses Tailwind CSS as its primary styling framework, layered with shadcn UI components and managed through a tailwind-merge utility wrapped in a cn helper function.

The Securo web application, located in the securo-finance/securo repository on GitHub, implements a modern, utility-first styling architecture. This setup combines the rapid development benefits of Tailwind CSS with pre-built, customizable UI primitives from shadcn UI, all orchestrated through Vite's build pipeline.

Tailwind CSS Integration Via Vite

The styling pipeline begins in frontend/vite.config.ts, where Tailwind is registered as a Vite plugin using the official @tailwindcss/vite package.

// vite.config.ts
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [react(), tailwindcss()],
});

This plugin-based approach replaces older PostCSS-based setups and enables faster builds with on-demand CSS generation. The Tailwind Vite plugin processes utility classes directly during the build, eliminating the need for a separate CSS compilation step.

Global Stylesheet Configuration

Tailwind's layers are imported in frontend/src/index.css using standard CSS @import directives. This file also pulls in shadcn UI's theming layer.

/* src/index.css */
@import "tailwindcss";
@import "shadcn/tailwind.css";

The first @import statement loads Tailwind's base (CSS reset), components (container, form controls), and utilities (spacing, colors, flexbox) layers. The second import activates shadcn UI's design tokens, including CSS variables for theming such as --primary, --background, and --foreground.

Class Name Management with tailwind-merge

To handle dynamic class composition, Securo implements a utility helper in frontend/src/lib/utils.ts. This wrapper combines clsx for conditional class handling with tailwind-merge for conflict resolution.

// src/lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

The cn helper serves three critical purposes:

  • Conditional classes: clsx evaluates boolean expressions and arrays to determine which classes apply
  • Conflict resolution: twMerge removes duplicate utilities, keeping only the last occurrence when conflicts arise (e.g., p-2 p-4 becomes p-4)
  • Type safety: The ClassValue type from clsx ensures proper TypeScript integration

Using the cn Helper in Components

Components throughout the codebase leverage cn to compose flexible, theme-aware class names:

import { cn } from '@/lib/utils';

export default function Button({ primary }: { primary?: boolean }) {
  return (
    <button
      className={cn(
        'rounded px-4 py-2 text-sm font-medium',
        primary ? 'bg-primary text-white' : 'bg-gray-200 text-gray-900'
      )}
    >
      Click me
    </button>
  );
}

Without tailwind-merge, passing both bg-red-500 and bg-blue-500 would produce invalid CSS with competing background colors. The cn helper automatically deduplicates, ensuring predictable styling.

shadcn UI Component Library

On top of raw Tailwind, Securo integrates shadcn UI—a collection of copy-paste React components built on Tailwind primitives. The library appears as a devDependency in frontend/package.json (v4 at time of analysis).

shadcn components arrive pre-styled with Tailwind classes but remain fully customizable. Developers can override any style by passing additional Tailwind utilities through the className prop.

import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';

export default function DashboardCard() {
  return (
    <Card className="shadow-lg">
      <CardHeader>
        <CardTitle>Overview</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="grid grid-cols-2 gap-4">
          {/* Content */}
        </div>
      </CardContent>
    </Card>
  );
}

The shadow-lg utility extends the base Card styling without requiring CSS module edits or inline style objects. This pattern—base shadcn styling plus Tailwind overrides—appears consistently across components like src/components/agents/markdown.tsx.

Dependency Overview

Package Purpose Location
@tailwindcss/vite Build-tool integration vite.config.ts
tailwindcss Core utility framework package.json
shadcn Pre-built component primitives package.json
tailwind-merge Class deduplication logic src/lib/utils.ts
clsx Conditional class construction src/lib/utils.ts

Summary

  • Tailwind CSS provides the foundational styling engine, integrated via Vite's official plugin in frontend/vite.config.ts
  • Global styles are configured in frontend/src/index.css with layered imports for Tailwind and shadcn theming
  • The cn helper in frontend/src/lib/utils.ts wraps tailwind-merge and clsx to safely compose dynamic class names
  • shadcn UI delivers ready-made, Tailwind-styled components that accept further customization through standard utility classes
  • The entire architecture favors utility-first CSS written directly in TSX/JSX, eliminating the need for separate CSS files per component

Frequently Asked Questions

Is Securo using CSS Modules or styled-components?

No. Securo's frontend does not use CSS Modules, styled-components, or other CSS-in-JS libraries. The codebase follows a utility-first approach with Tailwind CSS classes applied directly to JSX elements. All styling logic—static, conditional, or dynamic—flows through the cn helper and standard className props.

What version of shadcn UI does Securo use?

The repository depends on shadcn UI v4, as declared in frontend/package.json. This version ships with Tailwind v4 compatibility and uses CSS-native @import syntax rather than JavaScript-based configuration. The v4 release also introduces streamlined theming through CSS variables defined in src/index.css.

How does the cn function handle conflicting Tailwind classes?

The cn function passes classes through tailwind-merge, which implements a last-write-wins strategy for conflicting utilities. For example, cn('p-2', 'p-4') returns 'p-4' because the second padding utility overrides the first. This resolution happens at runtime, ensuring the generated DOM contains only valid, non-conflicting class strings.

Can I use arbitrary values with Tailwind in Securo?

Yes. Standard Tailwind arbitrary value syntax works throughout the codebase. You can write w-[123px] or bg-[#1da1f2] directly in components. The Vite plugin processes these at build time. For repeated arbitrary values, consider extending the theme in a Tailwind configuration file or using CSS variables mapped through shadcn's theming system.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →