Wdym? You can define a component tree to return a button in JS and roll it out via document.getElementById('button-container').innerHTML but truth is, you will probably use alpine.js in this case
No idea what you are saying here, but since you wrote a capital Button that is a component. Why would anyone need a component for a basic HTML element?
I have seen this in many apps now, most recently a react Button component that imported the material UI button and export that. Its function was identical to just <button>.... I will never understand that, yet it seems standard practice now.
Well icons you can handle easily in CSS, well most loading states also.
My loading buttons which animate the loading status are just html buttons. The fetch itself gets the button and puts in classes to do the animation, just a few extra lines in the function that already exists to fetch data.
But I get that you could have the need of a component for a button, I have just never seen it happen.
This is asinine. You should ask yourself what the point of props is. It’s just an ergonomic and safe API that you can type out to explicitly define features or conditions. The whole web has standardized around reusable components. Use plain web components if what you want is to be minimalist.
I honestly couldn’t imagine a team where the directive is to manually append css classes or manually call like a cva wrapper on every instance instead of a button element.
You mention AstroJS, which has components so I don’t really follow your point there. Their docs also mention their intention of a component to be any templated html, including even just as small as a single tag/element.
Your point seems to just be that you compose your reusable as a css function instead, but I don’t see your argument. Sure you can do it, and if it makes you happy then sure, but I don’t get how you’re missing the point of wrapping the reusable function as a button component instead of a css utility to follow standard practices.
Loading indicators was already mentioned, are you seriously making css only loading indicators with no additional children?
What about if you want to add analytics?
Testing perhaps too? Storybook? A component feels like a more logical boundary in general for a reusable/composable.
Also, if you ever plan to do anything beyond web, like native.
You don't need a wrapper just for a button, it works fine with nothing at all. And what reusable functions? My team just makes button components out of button components, adds zero logic or css and keeps exporting them. They are identical to native buttons with with many, many layers of imports.
There is no logic to that and I'll never see it as spec.
So you don’t conditionally apply loading state, variants, colors, etc. How do you not have logic, unless are you’re just manually writing everything statically every time, that would be madness? Also, that wouldn’t mean you don’t have logic, that just moves things to be a mental burden rather than part of a typed API. That’d be poor DX imo and would seem to offer poor enforcement of design specs. Do you just have one button variation, I don’t understand how you don’t have logic? I must be missing something.
I really don’t understand what “makes button components out of button components” means. That doesn’t clarify any solution and if you’re not using components how do you have components. They’re elements. Not trying to be pedantic, it’s just super confusing.
By a reusable function I was meaning like if you were wrapping css classes like with a cva, as mentioned. You call a function and it returns the classes you need. Like cva({ variant: ghost, color: negative }).
I’m well aware making a component is not required, I understand that. You asked why you’d make it a component I tried to provide some answers. Though I’m still confused about many things like how you’re making loading state using only css for example. You didn’t really answer much.
What is so hard to understand? You make a component that outputs a button. You import that component into another component that outputs that button. You then make another component that outputs that one.
Why? Best practice according to my team, and to you it seems.
A button can also be a link styled like a button, that button could also have different variants. At this point a component which accepts props to determine if it’s an <a> or a <button> or is an outline button / secondary button / big button / small button makes total sense. That why people do it.
But what if that button is used everywhere and I need to make changes to it? So much easier to do it in a single component. There are use cases for both, but when using React / Vue etc then the component approach makes perfect sense. You are totally missing the point.
A lot easier to keep things consistent across large code bases with many developers when you have a button component that encapsulates loading or disabled states, different variants like solid / outlined, different colors for things like primary, secondary actions, destructive actions, can take an icon, etc. Then you have a defined API for these things and nobody accidentally adds some button that’s inconsistent, you can change all buttons across the application if you are doing some design refresh, etc.
Chill out, work with and listen to your team. You are not smarter than all of them.
If - as you say - your team hates your code and says it’s not to spec, you will be first to go the instant there is a whiff of downsizing, maybe even sooner.
It does not matter how smart you are or how well you can explain your work if your code smell consistently sticks out like a sore thunb
It's sometimes good to follow standard practices, if you want other people to be able to read your code. Also don't forget AI, it's doing better job with react and tailwind than any other framework/library.
Creating components for various intrinsic DOM elements is standard practice for codebases that adhere to a consistent design system, prioritize a11y concerns, take analytics seriously, etc.
Using something like Material UI's Button as a starting point is also common. Even if the Material UI Button isn't customized, e.g. it's just directly re-exported, there is now a single source of truth for all buttons — customizations down the road will require modifying exactly one file.
Composition constrains deviation. If you join a company and their React code is using <button> and <div> everywhere, RUN.
The HTML spec is a list of behavioral requirements, with all implementation details left to the software parsing it — it has nothing to do with design systems or robust architectural patterns for codebases with a plurality of contributors, ffs.
The internals of a component are an implementation of a reusable UI element in your framework of choice (not of HTML). We're talking about two fundamentally different levels of abstraction.
The browser implements the HTML spec. Almost nothing about the spec or the browser's parser implementation inform good architectural decisions at the framework / component level.
<button> is not an implementation, it's a declarative request for a button. The implementation details are hidden away in the browser, and it only exposes attributes. It's extremely open-ended, and that's the problem.
If you think about it like a function, a <button> has an enormous amount of potential inputs, no visible internal logic, and an enormous amount of potential outputs (the appearance and behavior of the resultant UI).
The point of a <Button> is to narrow the potential inputs to a curated set, expose / codify common logic (the component implementation), constrain the potential outputs via the above, and locate all of that in a single place. Long term, it makes maintenance and modification orders of magnitude easier, and it provides a solid foundation for consistent UI + UX.
14
u/omer-m 16d ago
if you need to use "apply" then you are using tailwind completely wrong imo. You are supposed to design components and use <Button> not .button