Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
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.
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.
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.
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.
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.
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.
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.
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.
From React 18 to 19.3: Concurrent Rendering, Actions, use(), ref as Prop, Activity, useEffectEvent, ViewTransition and Fragment Refs
React 18 laid the base for concurrent rendering (createRoot, batching, transitions), 19 brought Actions, use() and ref as a prop, 19.2 Activity and useEffectEvent, and 19.3 stable ViewTransition and Fragment refs. We add ViewTransition and a Fragment ref to Bookstore, apply React Router 8.5's deprecation, and upgrade a small React 18 project to 19.3 with the 18.3 warnings, the TypeScript codemod and manual fixes.
A Brief Look at Next.js: Server Components, the App Router, Server Actions, Cache Components and When an SPA Is Enough
Next.js runs React on the server: Server Components await data directly and their code never reaches the browser, Cache Components let you choose what is cached with 'use cache' and cacheLife, and every Server Function is a public endpoint that needs validation and authorization. We serve Bookstore's book details as a Partial Prerender with Next.js 16.4, call a Server Function directly with curl, and discuss when an SPA is enough.
Finishing the Bookstore SPA End to End: Feature Folders, Authentication, Environments and Deployment
Getting a React SPA ready for production means guarding feature boundaries with a lint rule, knowing that VITE_ variables are written into the bundle at build time so secrets stay out of the browser, and handing the session to a BFF that uses an HttpOnly cookie instead of a token. We add a small ASP.NET Core and YARP BFF to Bookstore and show the sign-in flow, the SPA fallback, cache headers, an nginx config and bundle analysis with real output.
Testing React: Vitest, React Testing Library and Mocking APIs with MSW
The practical way to test React is to run React Testing Library, which queries the UI as a user does, on Vitest, which reuses the Vite config, and to fake the API at the network level with MSW without touching the code. In Bookstore we test the pure applyChange function, useDebouncedValue and useCart with renderHook, BookCard with user-event, and the catalog and checkout screens through the real route tree in a memory router, with real failures for getBy vs findBy and leaking store state.