Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
The Utility-First Approach: What Tailwind Solves, What It Costs and When Not to Use It
Utility-first writes styles inside the component with small, token-bound classes; the CSS grows with the number of distinct classes rather than components, and the price is long class lists and a learning curve. We measure the CSS and HTML cost of both models on three Bookstore components, solve repetition with a Razor partial, and show why @apply is the last resort, what Preflight does to CMS content and why unlayered legacy CSS overrides utilities.
Setting Up Tailwind v4 and CSS-First Configuration: @import "tailwindcss", @source and the Oxide Engine
In Tailwind v4 the configuration lives in CSS: @import "tailwindcss" puts theme, Preflight and utilities into three layers, and the Oxide engine scans sources as plain text and generates only classes whose full name it sees. We build the input.css → site.css chain in Bookstore.Web with the CLI, --watch and --minify, show why site.css returns 404 after a clean publish with BeforeTargets="Build", how .gitignore affects scanning, @source not/inline, and dynamic colors with --cat-color.
Themes and Design Tokens: @theme Namespaces, Custom Colors/Fonts/Breakpoints and Dark Mode
Every variable in a @theme block produces both a utility and a CSS variable on :root; the variable's namespace decides which utility appears. In Bookstore.Web we define brand tokens, compare extending the default theme with resetting it via --color-*: initial, measure why @theme inline is needed for per-institution colors and what @theme static does, build flash-free dark mode with semantic variables and a head script, and generate @theme from DTCG tokens with Style Dictionary.
Variants, Custom Utilities and Modern CSS: group/peer, data-*/aria-*, @container, starting:, @utility and @variant
Every Tailwind variant adds a selector or an at-rule; group-hover also reacts to an outer group's hover when groups are nested, which is why named groups like group/card are needed. With Bookstore's filter and card examples we measure peer, has-*, not-*, in-*, headless styling with aria-expanded and data-[state], @container and v4.3's @container-size, a popover animation with starting:, logical and scrollbar utilities, @utility (--default), @variant and @custom-variant in Playwright.
Tailwind with Angular: ng add tailwindcss, @reference in Component Styles, Dynamic Classes and Headless Components
In Angular, Tailwind runs on the global styles.css; component CSS is processed separately, so @apply needs @reference there and carries fallback values and @property blocks into every component. In bookstore-web we show what ng new --style tailwind and ng add do, the bundle and build cost of @reference across 40 components, why Tailwind syntax breaks in SCSS, dynamic classes with full names and signals, and styling an Angular Aria Listbox with aria-selected.
Scale, Maintenance and Versions in Tailwind: Component Patterns, Class Sorting, tailwind-merge and Migrating from v3 to v4
Of two conflicting utilities, the one later in the CSS wins, not the one written later in the class attribute; so components should expose variants through a class map with full names and merge outside classes with tailwind-merge. We build this into bookstore-web's button, show tailwind-merge's custom token pitfall and Prettier sorting, measure with Playwright what npx @tailwindcss/upgrade converts and misses on a v3 page, and lay out the v4.0–v4.3 release map.
Everyday Utility Families 1: Layout, Flex, Grid, Spacing, Sizing and Position Utilities
Tailwind's layout utilities map one to one onto CSS, and numeric values derive from a single --spacing variable; the hard part is knowing which CSS to pick. We build Bookstore's catalog grid, book card and two-column cart page both with utilities and with plain CSS, compare the boxes of both pages at three widths in Playwright (0px difference), and measure space-x breaking on wrapping rows, a missing min-w-0 and the difference between auto-fill and auto-fit.
Everyday Utility Families 2: Typography, Color, Border, Shadow, Effect, Transform and Form Utilities, the typography and forms Plugins
In Tailwind v4, border and ring default to currentColor, ring is 1px, scale/rotate/translate write to the individual transform properties, and once @tailwindcss/forms is added accent-* no longer paints the checkbox. We measure the hover shadow and cover scale on Bookstore's book card, grayscale for out-of-stock books, native controls versus the forms plugin on the checkout form, and the prose class on a CMS body in Playwright.