Remix.run Logo
ktpsns 3 hours ago

CSS in 2025: Let's write html inlined styles as if it was 2005 and separation of formatting/representation was never invented. I talk of tailwind, of course.

namuol an hour ago | parent | next [-]

The deadest horse in web development is the myth of “separation of concerns”

appplication 38 minutes ago | parent [-]

You can separate concerns without violating locality of behavior, and that’s exactly what tailwind does.

It admittedly does not do a good job at being very DRY but I think that’s poorly applied to HTML/CSS in general, and the most DRY css is often over abstracted to the point of becoming nigh uninterpretable.

nine_k 24 minutes ago | parent [-]

When I write CSS, I most often do not want the locality of behavior. I instead want uniformity of behavior, hence "semantic" styles. Even the trivial light / dark mode switching is pain with Tailwind, when classes like "color-gray-200" are routinely applied.

appplication 17 minutes ago | parent [-]

I’d somewhat agree with you there, but I usually use variables for uniformity. I do see arguments against tailwind but find anytime I’ve tried to do anything else it just feels like bikeshedding on internals for the same end result.

Really what I want to see is beautiful TDD for CSS so that uniformity can be enforced, but I’m not sure that exists.

nine_k 5 minutes ago | parent [-]

Variables are hugely helpful, I agreee. IDK about bikeshedding. I'm very used to writing React code that normally declares no styles for components at all, and having CSS that style components using 1-2 classes, specific to these components. Container components control margins, <body> controls general things like fonts.

It seems that what solves the problem is a good component library. "But I need red text here!" For what reason? It's a warning. OK, we've got <Text variant="warning">, it will be styled appropriately, and will look like every other warning in the application.

crooked-v 2 hours ago | parent | prev | next [-]

Tailwind is a direct response to how the "C" in "CSS" actually sucks, so there's no surprise that it's so popular.

mattlondon 2 hours ago | parent | prev | next [-]

Wait until you see React & JSX...

At least html and CSS are both presentation. React/JSX now confuses presentation and business logic.

lateforwork 2 hours ago | parent | next [-]

> React/JSX now confuses presentation and business logic

React was originally designed to be the "V in MVC". You can still use it that way. React becomes very simple when you only use it as the V in MVC.

azangru 2 hours ago | parent [-]

What are the M and the C, and how do they talk to the V in this case?

lateforwork an hour ago | parent | next [-]

M stands for Model layer. This layer handles business logic and knows nothing about UI. It does not have any html or CSS.

V stands for View. This layer handles HTML and CSS. You can use React here.

C stands for Controller. Controllers know about Views and Models and which model objects to instantiate for which view. It makes REST API calls and does caching, and handles errors. Controllers know about the application state and decide what page to display next.

For an application written in this style see: https://github.com/wisercoder/eureka/tree/master/webapp/Clie...

(This app doesn't use React, but does use TSX, and you could use React as well).

apsurd 2 hours ago | parent | prev | next [-]

react can be pure functions that take in props. Given a set of props, ideally data primitives, the outputted view is guaranteed. it's nice.

In practice, the entire JS ecosystem enjoys flying off the rails, every season, but it's not strictly react's fault.

To answer your question, however those props get into the component is up the the M & C. can be async server, or shoved in as json in the script tag.

azangru an hour ago | parent [-]

If you move the data (the M and the C) entirely out of react, and only pass it in via props, there would be only one place — the root react node — where the props could get into react. Is this what you have in mind? Or are you envisioning multiple root nodes?

apsurd an hour ago | parent | next [-]

Well, i've always been a fan of the island architecture that effectively mounts root nodes as little islands of isolated state, yes.

Mainly this avoids the hell that global state SPA patterns produce: redux, reducer patterns in general, and 8 thousand context providers.

I do think there's use cases that warrant global in-memory state, but it's such a pain in the ass to maintain and evolve, i'd always plan against it. Every html node in your app does not need to know about literally everything going on and react instantly to it. it just doesn't.

Just make another page!

Also: so the islands pattern can be as fancy or rudimentary as desired. they can bootstrap themselves via async endpoints, they can be shipped as web components even, or they can be static, pre-hydrated in some manner.

kittbuilds an hour ago | parent [-]

The islands pattern is underrated for maintainability. I've found the biggest win isn't even the state isolation — it's that each island can have a completely independent upgrade path. You can rewrite one island from React to vanilla JS (or whatever comes next) without touching anything else.

The global state SPA pattern fails for a more fundamental reason than just being painful to maintain: it creates an implicit contract between every component in the app. Change one reducer and you're debugging side effects three layers away. Islands make the contract explicit — each one owns its data, full stop.

The one gotcha I've hit is cross-island communication. PostMessage works but gets messy. Custom events on a shared DOM ancestor end up being the cleanest pattern for the rare cases where islands genuinely need to coordinate.

tim1994 an hour ago | parent | prev [-]

With signals you can avoid the prop drilling. I think signals can help a lot with this approach

azangru an hour ago | parent [-]

I think the parent wants to separate the V from the M/C. If you smuggle signals inside of components to avoid prop drilling, you would be coupling the M/C and the V. I suppose that's not what the parent has in mind.

cbarrick 2 hours ago | parent | prev [-]

- M for Model: your data model. - V for View: views of your data. - C for Controller: does stuff with your data.

madeofpalk an hour ago | parent | prev | next [-]

I think you're confusing business logic with view logic.

bromuro an hour ago | parent | prev [-]

React is great for MVVM indeed. Who is still using MVC in 2026?

interlocutor an hour ago | parent | next [-]

Ever heard of Django? ASP.NET? Most UI frameworks, including ASP.NET Core, Spring Boot (Java based framework), Ruby on Rails, and Django (Python) are all based on MVC.

flowerlad an hour ago | parent | prev | next [-]

MVVM was invented by Microsoft for 2-way syncing in WPF. Today we know 2-way syncing is a mistake.

Who uses MVC in 2026? Pretty much every framework out there, including Java frameworks and Python frameworks and .net

ozim 6 minutes ago | parent [-]

You have any more sources on MVVM being a mistake?

I found WPF rather nice to work with. Same with knockout.js and Angular I don’t see much downsides.

Everyone can write bad code of course in each of them but I think it was working quite well.

techpression 43 minutes ago | parent | prev [-]

Adding to sibling comments, Phoenix. And it’s a damn nice experience at that.

h4x0rr 3 hours ago | parent | prev [-]

Yeah let's do that. You have everything related to your component on place instead of jumping between files.

lawn 2 hours ago | parent [-]

Is jumping between files supposed to be difficult or something?

afiori 2 hours ago | parent | next [-]

Without a lot of discipline it is very easy to end up with a css with lots of unclear and hard to guess effects. Eg consider the case of <A type=1><B><A type=2></A></B></A> where A and B are complex templates. Any selector with the " " operator on A risk expanding to the inner A even if it was intended only for the outer. Similarly a :has selector might catch a descendant of the wrong element.

@scope fixes a lot of this, but it is a complex problem. With tailwind you mostly have to worry about inheritance

robertoandred an hour ago | parent [-]

This problem was solved a long time ago with CSS Modules.

christophilus 26 minutes ago | parent [-]

I prefer almost anything to CSS modules, so this bike shedding topic is probably very subjective.

chrisweekly 2 hours ago | parent | prev | next [-]

Colocation is a useful principle in component-based architecture.

apsurd an hour ago | parent [-]

In my lived experience, shared components just become another problem. Especially in a fledgling company, the iteration velocity is actually negatively affected by shared libs because there's always overhead to (not) break legacy. so shared components bloat to address every evolving need.

And now with AI generated code i see so many wrapper patterns that forward endless props down, it's crazy!

TLDR: i almost always end up branching out into evergreen "reusable" components anyway.

Very unlikely the component library the CTO asked claude to DRY up the code with, is the one to rule them all.

runarberg 2 hours ago | parent | prev | next [-]

Also modern CSS is often written in a <style> tag either in a native web component or in a framework which supports single file component like vue or svelte.

ewuhic 2 hours ago | parent | prev [-]

Is staying in one file supposed to be difficult or something?

luckylion an hour ago | parent [-]

this is grey text from tailwindcss.com, I wouldn't call it easy and readable.

<div class="relative before:absolute before:top-0 before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10 before:-left-[100vw] after:absolute after:bottom-0 after:h-px after:w-[200vw] after:bg-gray-950/5 dark:after:bg-white/10 after:-left-[100vw]"><p class="max-w-(--breakpoint-md) px-2 text-base/7 text-gray-600 max-sm:px-4 dark:text-gray-400">Because Tailwind is so low-level, it never encourages you to design the same site twice. Some of your favorite sites are built with Tailwind, and you probably had no idea.</p></div>