Replies: 1 comment 1 reply
-
I'm sorry, but I feel compelled to address your points. Your critique appears overly focused on discrediting Tailwind without an objective assessment, seemingly with the intent of promoting your component-based approach from your theme stack. As a Tech Lead working with industry-leading merchants using Shopify, I want to provide a counterpoint rooted in experience. This thread deserves balance, so I will address each of your arguments with practical examples and facts. Flexibility and CustomizationGlobalThe
And pass the value however it fits you the most, eg in your theme file :
Sections/Snippets/BlocksStaticTailwind build tool build the css classes that comes from your liquid files (and more), and thus the one you declare in the schema.
DynamicYou can leverage the widely compatible native custom css variables if you need something more granular :
Build Tools and PerformanceThe decision to remove build tools from the development pipeline is understandable, but it significantly limits the benefits of modern frontend development (like using typescript, bundling, minimization etc). Tailwind's build process is not just about generating utility classes; it also includes critical features like purging unused styles, which is essential for performance. Shopify's own development tools, like the Shopify CLI, are compatible with modern build processes. By leveraging these tools, developers can use Tailwind efficiently without sacrificing performance or simplicity. Furthermore, css assets are cached by the browser, if you keep it simple, using Tailwind allows to have only one minimized and purged asset file that will be cached and used across all the website. You will be surprised to see the loading time of a built Tailwind css file compare to one simple component css file on a Shopify. Collaboration and scalabilityClear Naming ConventionsTailwind's utility classes use consistent and descriptive names, it make it easier to understand and work with the styles, even in team. Reduced CSS ConflictsThe utility-first approach minimizes the risk of style conflicts that can occur with traditional CSS methodologies. DocumentationThe documentation is maintained and the community growing. The probability of having a widely used Shopify theme css architecture documentation that can reach the level of Tailwind's one is most probably close to 0. Last but not least, I find it somewhat hypocritical that you criticize Tailwind while you’re literally using some of their naming conventions in a CSS variable file (also here) with the exact same values from the Tailwind documentation. I don't know all your stack, and you have for sure good reasons to not use Tailwind, but to me, the key is to see Tailwind not as a rigid system, but as a flexible framework that can be adapted to the unique needs of Shopify theme development. |
Beta Was this translation helpful? Give feedback.
-
Note
The focus of this write-up is to explore a world where we aim to develop themes without build tools. This is something we’re actively experimenting with to see how far we can push the concept, which is what inspired this post.
Tailwind CSS has transformed the way we approach web development by championing a utility-first methodology. Its promise of keeping developers "in their HTML" resonates in modern component-based workflows where self-contained components and advanced build tools reign supreme. It's a game-changer on many levels!
But what happens when we take this approach into the world of Shopify theme development? A world where configurability, merchant-driven customization, and the absence of build tools are the norm. Here, Tailwind's strengths can quickly become limitations.
Take the simple example of managing a gap between grid items. In Tailwind, you might use a utility class like
gap-1
to handle this. But what if a merchant or theme developer wants to configure that gap value? Utility classes likegap-1
are static by nature, tied directly to your HTML, and fail to accommodate dynamic requirements. Changing this togap-2
wouldn't work unless you brought over the corresponding CSS as well. This creates a dilemma: should layout-critical styles like gap remain hardcoded in the HTML, or should they live directly in the CSS?The unique demands of Shopify themes
Shopify themes introduce challenges that don't align neatly with utility-first CSS methodologies.
Dynamic, merchant-driven customization: Shopify themes must prioritize configurability. Merchants expect to modify styles via settings or directly in the theme editor. This dynamic nature is at odds with the static utility classes that Tailwind empowers developers with.
Build-tool-free environments: For simplicity and maintainability, we've chosen to remove CSS preprocessors from our development pipeline. Without tools like PostCSS, Tailwind loses its ability to generate utility classes dynamically.
Collaborative and scalable requirements: If you're a solo developer working on a bespoke project for a single client, Tailwind will probably still work well for you. However, when developing themes for the Shopify Theme Store—where merchants need customization options and other developers may extend or configure your theme—the complexity quickly escalates. Tailwind's approach doesn't account for these multi-layered use cases.
The pitfalls of partial utility class adoption
An obvious workaround might be to hardcode a subset of utility classes, but this brings significant challenges:
md:
,hover:
) multiplies the required class definitions. The result is bloated, difficult-to-maintain CSS.Fragmentation of styling architecture
Without build tools, relying on utility classes fragments your styling architecture. CSS becomes scattered across Liquid files and separate CSS files, creating multiple sources of truth. Consider this example:
In this case, the grid utility class in the HTML sets
display: grid
:Meanwhile, the gap property—essential for defining the layout spacing—is handled by an additional class,
product-grid
, in a separate CSS file:At first glance, this might seem like a logical separation of responsibilities. However, this split creates an awkward inconsistency. The grid utility class defines the overall layout (
display: grid
) directly in the HTML, while spacing—an integral part of that layout—is managed elsewhere in the CSS. This disconnect forces developers to jump between multiple contexts to fully understand or modify the component's styles.This issue becomes particularly problematic as components grow more complex or need customization. Developers are left wondering: Should layout-related styles, such as spacing or alignment, go into the CSS alongside gap? Or should they be added directly to the HTML as more utility classes? The result is an inconsistent and fragmented system where it's unclear where the "truth" of the component's styles resides.
Over time, this fragmentation increases the cognitive load for developers and introduces unnecessary friction into the workflow. Instead of maintaining a cohesive styling strategy, the team is forced to navigate a scattered approach that makes the codebase harder to maintain and extend.
Responsive design challenges
Handling responsive design manually without build tools further complicates matters. Every utility class requires explicit media query definitions:
Scaling this approach for multiple breakpoints or custom themes quickly creates unmanageable CSS bloat. The simplicity of Tailwind's generated classes evaporates without its underlying tooling.
Impacts on development workflow
The hybrid approach of mixing utility classes and traditional CSS introduces significant cognitive overhead:
Again, for a solo developer on a small project, this may not be a concern. However, when building themes for broader use—especially for the Shopify Theme Store or multi-merchant environments—the increased complexity can slow progress and erode a team's ability to deliver consistent results.
Our component-based approach
At Archetype, we've adopted a component-based approach where each component has its own
main.css
file. This allows us to focus entirely on the CSS for that specific component, without mixing responsibilities across files. While we've removed CSS preprocessing from our build tools, we still rely on simple build tools to compile thesemain.css
files into a single CSS bundle.This approach isn't perfect, and we're gradually improving it to make it easier for other theme developers to leverage this framework by emphasizing maintainability and simplicity.
Conclusion
Utility-first CSS frameworks like Tailwind are incredible for component-driven development in modern web applications, but their methodology struggles to address the unique challenges of Shopify theme development. When working in build-tool-free environments that prioritize merchant customization and scalability, we're finding that the introduction of a hardcoded set of utility classes can lead to complexity, inconsistencies, and technical debt.
While Tailwind champions "never leaving your HTML," perhaps the reality of Shopify theme development is that we're perfectly fine stepping out—and fully embracing our CSS. After all, the goal isn't just convenience; it's building scalable, maintainable, and merchant-friendly themes.
For the record, this post isn't a rejection of Tailwind—we actually love it. However, it is an exploration of our own personal challenges we're facing as theme developers.
We're eager to hear from other theme developers: do you share these sentiments? Or have you found strategies to effectively bridge the gaps between utility classes and good ol' CSS?
Beta Was this translation helpful? Give feedback.
All reactions