You seem to trying to express a negative response to the fact that these companies create design frameworks. I'm interested as to why you feel this way?
I didn't read it that way at all, it's simply highlighting that there's a large number of options to chose from! It's great that more companies are publishing their design frameworks, although part of the reason for doing this is certainly to attract talent.
Having partially reviewed a couple of these, I'd say quality varies quite a bit so be sure to dig through the code to see if you'd be comfortable helping maintain that. Always be sure to review the license! For example, Microsoft Fabric is MIT, but the assets (fonts and icons) are under a separate license.
In a way yes, it was about the utility and relevance of Yet Another Corporate Design System. I couldn't find what I really wanted to post, which was a list of all the abandoned Corporate Design Systems - I think I must have seen that in another comment.
The universal certainty of expansion and contraction. Hey we all got here through it. Now we're in the expansion phase of trying to make the frontend easy again. Contraction comes next.
Unscientific review from my FHD Dell laptop on Ubuntu too dim for a room without curtains: Bootstrap and Material consistently succeeds in rendering clearly; Ant is fine; Fabric from MS has a very readable site, but their Office apps tend to have tiny labels without contrast; Ring by Jetbrains is also perfect but I had to switch to light mode on my IDE since warning squiggles were too dim, Github AT had issues with grey on white and grey on grey.
Other sites tend to have rendering issues with some lines in letters either becoming doubly thick or barely visible, white text pixelating out to bright backgrounds, anti-aliasing turning some pixels colorful or too dim etc. Some of them seem to be exposing edge cases of text rendering! Text could be too gray to read or too thin.
Designers need to consider people still buying laptops with 1366X768 screens.
They're all still big and bloated (like including big sets of icons) but you should only only include what you're using. Tree shaking with webpack and babel and a css optimizer can trim them down significantly.
There's definitely still issues with that though. Try including one small component from material UI for example and the resulting bundle can still be quite significant because it bundles a lot to manage its theming.
The overrides pattern they describe sounds like a nightmare to maintain. It's almost the exact opposite of how I'd design the API for a set of reusable components: provide a minimal API surface to cover existing use cases, and evolve the API deliberately to cover new use cases as they arise.
Allowing users to override arbitrary styling parameters is a recipe for disaster in a reusable component, because once you start doing that, literally any change you make to the component could become a breaking change for some usage of it in the wild. There is no more explicit interface that users of the component are expected to work with that you can hide implementation details behind, as to afford you the ability to change those implementation details without breaking users, because users can just reach into your implementation details with those arbitrary parameters and change them at will, in a way that's potentially incompatible with how you might want to evolve the component in the future. As a side effect, any sense of brand/design consistency you might want to enforce through a design system goes out the window. Interestingly enough, this set of components use component-oriented CSS-in-JS, which is a pattern developed specifically to provide style isolation between components that wasn't possible (or at least not in a foolproof way) with regular CSS, yet they chose to open that can of worms back up through their API.
I've found that a much better middle ground is to deliberately accept React nodes or render props in your components so that you can explicitly yield control of rendering to users for specific, isolated pieces of the component, like the contents of a modal or the individual options of a dropdown. This gives users freedom to render what they need to render, but within the confines of a consistent design framework that enforces overarching rules around consistent use of spacing, colors, transitions, etc. And such an API can still be evolved deliberately to support new use cases without the risk of breaking users unintentionally.
I get this concern and I used to have a very similar feeling about it. Uber had an older React component library that was more locked down in a way you pretty much described. Number one complain was "not easy to customize" and that probably applies for every component library out there.
You describe render props as a "middle ground". For us, it is the last resort / nuclear option (as described here https://baseweb.design/theming/understanding-overrides/#over...). You give the consumer all the freedom to completely replace the guts of your component. Sure, nothing provides more flexibility but at the same time, consumer has to do a lot of heavy lifting - creating a whole new component.
However, developers usually want to tweak some small things. Maybe changing some color or padding. Forcing them to swap the whole subcomponent through render prop is an overkill and once they "opt-out" that way, they will never get any updates from us since that part of component is completely replaced.
Of course, ideally we want them to always use the defaults but that's not how real organizations with thousand of engineers and hundreds of apps work so we rather let them customize but on our terms. We don't want to see them hacking the styles through CSS selectors or "render prop" everything which equals not using our visual components at all. It's a compromise we had to make to make everyone reasonably happy.
Surprisingly, it's not a nightmare to maintain. We don't consider changed styles as a breaking change and in last 6 months I haven't seen complains about that. Although, it makes the Base Web codebase more complex and all changes need to be thoughtful. But that's a cost that Base Web pays so other teams don't have to.
Do you use any sort of visual comparison tools or snapshotting in CI to catch regressions caused by changes to Base? Seems like this would remove any (technical) objections to having overrides.
We currently use https://screener.io/ for Base Web itself and working on an app that should automatically crawl all our web apps, analyze them and provide insights into how exactly our components are being used. It should be open sourced eventually.
I can appreciate that you guys weighed the tradeoffs and decided that giving users freedom to override arbitrary styles is worth the cost of whatever breakage might result from that decision as you upgrade the library. We're all engineers who build things to solve real world problems at the end of the day, and I don't have any of the context that led up to your decision, so I can't say for certain that I'd have weighed those tradeoffs any differently if I were in your shoes and have to cater to the whims of thousands of engineers with differing opinions on how things should be done.
However, I have to disagree with your characterization of render props as "the freedom to completely replace the guts of your component". Offering a render prop API should be an explicit decision to fundamentally stop treating that branch of the render tree as part of the "guts of your component". It's a decision to delegate to users on how to best render that part of the component.
Of course, you're right that in a vacuum, that would equate to throwing up our arms and asking users to figure it all out on their own as to how to implement the styling and functionality of that part of the tree.
However, when we're the maintainer of a component _library_, we're in the unique position where we can provide additional, complementary components that provide styling and functionality for users to use to implement that part of the tree, composed with their own custom components when appropriate, without having to build everything from scratch.
These components usually start out as the same components that used to reside in that part of the tree in the original parent component. By decoupling them from the parent, they're then immediately able to start providing their own explicit interfaces that can be evolved independently from the parent without risk of breaking usages on implementation detail changes.
Of course, users are free to simply not use those components because they might not address whatever problem they need to solve. Rather than taking that as a failure of the approach, I'd take that as a triumph because it demonstrates that this approach gives users the flexibility to experiment with how best to solve their particular problems within the confines of the isolated subsection of the original component without affecting the maintainability of the component itself. And we as library maintainers are then able to examine the various custom components created for those use cases to see if any particular implementation is suitable for extracting directly into the library, or at least learn from them when building new reusable components to support those use cases officially (and users are free to choose to adopt those new components at their own pace, without any fear of things breaking under their feet).
This is why I point to this approach as the middle ground. Component composition is a much more sustainable mechanism to provide to users for customization, in my opinion, compared to arbitrary overrides. In fact, if anything, I'd consider arbitrary overrides to be the nuclear option here, because once we start offering that option, people are going to start using our components ways that we can't possibly ever fully anticipate, so we end up having to _really_ throw up our arms as maintainers and start saying things like "We don't consider changed styles as a breaking change".
Right. We do exactly that as well. You can import all our styled subcomponents separately and then plug them back into render props. We just call it a bit differently - it's the "overrides" object prop and not a top level renderFoo prop. Example: https://baseweb.design/theming/understanding-overrides/#over...
The ability to extend the styles is just a shortcut. If I want to change a border for some specific subcomponent, I could import it, change the color (in our case through a css-in-js API) and plug it back through a overrides.FooComponent.component (which is nothing else then a render prop).
But that's a lot of steps to just tweak a border, isn't it? Why not to just have "overrides.FooComponent.style" and let the library do the rest. This doesn't open more surface, just a quality of life API. Arguably you can run into the same type of style breakages when devs are restyling our subcomponents. They will not look inside of them every single time we release a new version.
To be honest, the only really unique thing about Base Web is that you can replace every single subcomponent (1 subcomponent always renders 1 styled DOM Element) through render prop pattern and you can even do it in a layered fashion (passing children through). "overrides.Foo.props" and "overrides.Foo.style" are just shortcuts for render props. Other than that, it's just an another React component library.
"people are going to start using our components ways that we can't possibly ever fully anticipate" - That always happens no matter what you do! Unless you make your API super strict and then nobody will want to use your library. It's a delicate balance - keeping other teams moving fast and happy while not introducing breakages often.
> But that's a lot of steps to just tweak a border, isn't it? Why not to just have "overrides.FooComponent.style" and let the library do the rest. This doesn't open more surface, just a quality of life API. Arguably you can run into the same type of style breakages when devs are restyling our subcomponents. They will not look inside of them every single time we release a new version.
The ability to arbitrarily override styles in every single component exposed through the library is exactly the crux of my concern outlined in my original post and later reply.
> "people are going to start using our components ways that we can't possibly ever fully anticipate" - That always happens no matter what you do! Unless you make your API super strict and then nobody will want to use your library. It's a delicate balance - keeping other teams moving fast and happy while not introducing breakages often.
Yes, there's definitely a balance to be struck here.
Opening up the API to arbitrary style overrides is sitting at one end of that spectrum, optimizing for short term user freedom/productivity and quick adoption of the component library over the long term maintainability of the library (every change becomes a potential breaking change), and with it, the ability of users to upgrade with confidence to take advantage of new changes and features.
However, the alternative to the wild west approach of arbitrary styling overrides isn't only to make an API so strict that it will never fit anybody's use cases outside of the ones it was originally designed for.
There exists a middle ground of providing an explicit API designed for specific use cases and then deliberately growing that explicit API to cover more use cases, informed by real world usage patterns, while taking care to make sure that those use cases are actually ones that make sense for the library to support long term (rather than built as one-off usage specific components), and that the resulting changes aligns with whatever styling consistency standards the library wants to enforce.
This approach affords maintainers an API surface to reason about and communicate breaking vs non-breaking styling changes to users, in exchange for short term speed of adoption because we're deliberately limiting the initial breadth of use cases the library can cover.
The former approach could definitely be the right tradeoff to make at this time given Uber's current circumstances.
Personally, I still have my doubts, after seeing how quickly this kind of API can break down even at a much smaller scale, but ruling that out without any context would be pure hubris on my part.
However, one caveat I'd like to add is moving from an explicit API to one that allows arbitrary overrides is easy, because adding an arbitrary overrides system is a non-breaking change, but going the other way is another story, because doing so would break everybody that relied on the overrides system to cover whatever use case the base API ever bothered to grow to cover, so it's not a decision to be made lightly. This is definitely not meant to imply that the team at Uber made the decision lightly, as I can tell from your thoughtful responses that you certainly did not, but rather as a word of caution to anyone else who's thinking about going this route.
Note that the above mostly applies to company/product specific component libraries where maintaining design/brand consistency is of great importance. For components meant for public consumption, I personally would only use libraries that yield _all_ rendering decisions to the user: not just styling, but the components being rendered as well as the way in which those components are composed.
Usually that means providing state & handlers through a render prop API, so users can compose their own styled components in arbitrary arrangements that wouldn't be possible with an interface that only exposes specific component overrides inside of a rigid structure. See downshift as an example of a library that does this really well (https://github.com/downshift-js/downshift), and contrast that to something like react-select that only offers the ability to provide overrides for specific components in its own predefined render tree (https://github.com/JedWatson/react-select).
Perhaps on top of that you can also provide a reasonable styled default, but not offering low level control of rendering is usually a deal breaker in my book when picking third party components to work with.
I think there's a big difference between Downshift and Base Web. Downshift is a low-level component offering powerful behaviors that you can use to build your own UI widgets, etc. Base Web looks more like a set of ready-to-use UI widgets. You use it because you specifically want a button that's styled and works the Uber Base Web way. Uber wants all of their buttons to look consistent, so obviously Base Web is going to have styling built into it. Maybe Base Web's button could be implemented using Downshift. If you don't want Base Web's button styling, then you're not Base Web's target audience. You're probably best off implementing your own button using Downshift too.
That's just partly true. From the Base Web website:
"Base Web is a set of reusable React components that implements the Base Web design language and can be used in two different ways:
To build an application that fully adopts the Base Web design language, you import and use Base Web components out of the box.
To build a new design system inherited from the Base, you take Base Web components and customize them through the Overrides mechanism.
If you are building an application using the Base Web design language (the first scenario), you should avoid further customization. This helps to keep the design of your application consistent and makes future upgrades easier."
Uber uses Base Web in both ways since there are some additional related design systems (historic reasons) and that's why a lot of effort was put into overrides.
Nope. This is replacing composition with configs for no good reason. It's like the people who made Grunt and Webpack teamed up to ruin React for everyone.
They laid out pretty well what problems this is trying to solve, why they want it that way, the benefits it has, and some of the tradeoffs it makes.
Saying it "replaces composition with configs for no good reason" is not only wrong (they still heavily use composition here, it even makes it more powerful in some ways from what I can tell so far), but also doesn't really mean anything on it's own (at least to me it doesn't).
And there’s already a multitude of ways to adapt styles based on props, the most obvious of which is StyledComponents.
In addition, this highlevel config is brittle. It means parents must be coupled to their children, and children coupled to their parents.
And where does this config end? How deep does the nesting of this configuration go?
Here’s my opinion; if you think you need this sort of configuration to properly wrangle your UI, then you’ve failed to grasp the point of React and the true power of composition.
React components are just functions. Preferably pure functions. Once you strip away the JSX, you should be left with something that resembles functional programming (albeit taken to an extreme thanks to JSX’s goal of emulating HTML). Props are parameters. We’ve all come across code where functions take complex and convoluted objects as arguments that trigger an explosion of calls that are near impossible to track or reason about.
This override solution is the first step in towards turning React into the kind of tool that it usurped. It has the stench of ExtJs and it’s ilk.
This “solution” was created by people who believe all problems are better solved by abstraction.
As programmers, our time is spent on the edge cases. Our text book prefect algorithms and mathematically sound functions are exposed as frauds the second they’re exposed to user input. Our carefully crafted UI libraries fall to pieces when the designers choose to break their own rules.
For configuration to work, it requires god level foresight and will eventually become Turing complete in itself.
Config is for the birds. Declarative code has always been the answer.
For render props, the BaseWeb API is not <Select renderDropdown={...} renderArrow={...} renderLabel={...} /> but it's collapsed under a single prop overrides={{ Dropdown: { component: {...} } ... }} naming convention. This "map" includes (and gives you access) to every single subcomponent.
The same goes for "adapting styles based on props".
BaseWeb uses exactly same patterns and techniques that you mention. The difference is the naming consistency and uniformity across all components. Instead of "littering" the top level API, we have a single prop "overrides" and instead of deciding what should and shouldn't be customizable, everything is customizable. Again, without a need to keep adding new top level props.
I didn’t propose the solution to a Select input that you said I did. There’s no need to define multiple render props since the most complex of selects is going to be a nested tree structure. Each node of that tree can be passed as an argument to the render prop, and the render prop itself can conditionally render any number of children types.
Everything is customisable without this override solution. And I’d argue that things become less customisable with it. What if the CustomOption component needs to be customised too? This solution makes a mess of that type of composition.
What you describe in the first paragraph is exactly what you can do with overrides as well. Again, it gives you access to any subcomponent in the component and you can replace it with your own component.
Note, that you can replace a single layer and pass the "children" through OR "replace the whole branch" of subcomponents when NOT passing the children through.
Also all overrides get various state props. For dnd-list, it can be something like $isDragged, so you can conditionally render different things.
At the same time, every Base Web component is exporting all these subcomponents. For example, component DND List also exports:
You are free to use these Styled subcomponents and recompose them any way you wish. You can build your own component from scratch (this approach works great for tables) or you can use overrides and utilize existing state handling etc.
Give me specific example: What customization of dnd-list you can't make with the existing overrides API and what other API would allow you to do that better.
That is not better. Just look at what you've created vs the idiomatic way of accomplishing the same thing with vanilla React. It's a new DSL on top of React that just adds unnecessary noise. It over complicates what should be a simple task.
Why do I have to specify "List" twice? And what sort of magic is "component" performing? What are children now? Do they not exist anymore? And what does "overrides" mean in this context? Passing children to a component is not an "override".
I think you're drunk on your own hype buddy. Maybe this all makes perfect sense to you, but it looks like garbage to me.
As a person reading this who was ready and waiting to celebrate a better standard way to override custom components... These two examples are night and day. Vanilla is way less convoluted. There better be a very convincing argument (and I guess I'll go read the official Uber reasoning) that explains why this extra magic is necessary.
I think you're being overly harsh. Literally the only difference is
overrides={{ Item: { component:
instead of:
renderItem={
(personally I'd probably have a shortcut to allow leaving "{ component:" off though)
I don't think that's a bad tradeoff to render props support (plus prop/style overrides) support across your entire component library in a consistent way.
A big part of the goal with the overrides mechanism was to provide usable components out of the box that could optionally be modified if something needed to be changed for a given use case.
You can use the components as is, using props if you're ok with the out of the box style/functionality/etc, without ever touching overrides. The overrides provide a standardized interface to changing the component internals across the entire component library.
That approach may be overkill for simple components that are trivally composable (Card for example), but is incredibly powerful for a component like Datepicker where you may want to change styles or functionality of a deeply nested component without exposing a massive top level props interface.
That feels a bit strange as a design philosophy; the point of components is that they encapsulate implementation and offer a simple, unambigious interface for configuration.
If someone needs a component to do something it doesn't do, that's a sign that the primitives are wrong and the component needs to be refactored. Punting the solution back to product teams is prioritising short terms wins at the expense of long term pain.
Imagine if we extended this philosophy to other paradigms: every method and property on a class is public and overridable, just in case we need to change the behaviour.
I disagree- the default use case is still to use the components without overriding. Having a well defined mechanism for changing the component allows for consumers of the components to still get the main benefits of the component and the owners/maintainers have better visibility into what (if any) changes may need to be made to the core components.
Referring to the Uber Freight RadioGroup and Tag Edit overrides from that article (not my article to be clear), those are cases where the vast majority of functionality from the original components satisfied the usage requirements, but a small tweak was needed to get the desired outcome. The override pattern is simply a way of building flexibility into the components and acknowledging that the users of the components may want to change them in ways that were not obvious to the component author. Those two examples may be fairly straightforward, but at what point do you stop with exposing the ability to change things? In our prior component library we saw a number of cases where teams wanted the ability to customize things that were more subtle, ie- changing the html element type on a subcomponent for a very specific purpose. This pattern came from observing the usage of our prior internal component library and talking with many of the internal consumers. It's probably not be a fit for everyone, but it works well for us.
But you’re still creating a suite of components that can be composed to create a specific instance of a date picker. Except with the override config, you’re now complicating and limiting the simple and versatile concept of composition.
Your components now need to follow some pre established and short sighted rules in order to understand how to manage their own children.
To use the example in the article, lets say you have an Option component, but now you want a version of that component that takes two additional components under certain conditions. E.g, an icon, and a checkbox? But only when one specific Option has a specific combination of props?
How does this override system handle that? It doesn’t. Composition handles that. But if components are created with this override system in mind, they lose the ability to be composed in more complex ways than the designer of the override system imagined.
It turns out I was wrong about this, but not in a good way.
It appears you can pass functions to the config that render components, which presumably can also take an override config which in turn can take a function to render components and so on. So it's basically negating the entire point of JSX. It's halfway between JSX and React.createElement. The worst of both worlds.
I've been searching for a basic React UI component system for awhile now. There are a lot of systems available, but each one has significant drawbacks to the point I end up just rolling my own.
I think an ideal system would have a core set of "unstyled" components with the necessary functionality baked in. That way the overall aesthetic is up to you, but a lot of the painstaking UI work (e.g. showing, hiding, and highlighting elements in a dropdown menu or making sure a layout element breaks properly on mobile) is already done.
From there you could build UI "kits" that use the core functionality but each have a distinctive look and feel.
For the past few years, i’ve been building “reusable component libraries” and I can say with confidence that they’re a massive waste of time.
When you get into it, the UI usually the least difficult problem to solve in an app. The real challenge is state management, control flow, and wrangling sode effects.
Alas, people are still wedded to the idea that UI is where all the time is wasted.
The truth is, it’s always been easy to put a button on a screen. But making that button do something? That is a much bigger problem. I’d argue that 99% of the effort of putting a button on a screen goes into implementing whatever that button does. But stakeholders don’t understand that. They think buttons just do the thing they do, so when it takes six weeks to put a button on screen, they naturally assume that a reusable component library that includes a button will somehow shave days and weeks off a project.
Which is why they gravitate towards UI libraries. And then they introduce a new problem that wasn’t there before. They want us to use Material UI, but they want us to make it look different. And they want a bunch of extra UI elements to boot. So not only do we still have all the original problems of creating an app, we’re now on the hook for turning some implementation of Material UI into something that fits with with our architecture, but is also completely different.
So while I hate UI libraries, I recognise that they’re something inflicted on a team. So I’ve started work on a UI library designed specifically to address this problem. It’s a UI library that’s meant to be changed and easily customised by it’s consumers. It’s minimal functionality and minimal styling. I’ll announce it here on HN when I think it’s ready. It may never be ready because not only is it a difficult problem to solve, I’m also very lazy.
But anyway, I say all this because I hear what you’re saying, and I’m working on it.
I've been using reactstrap and since it relies on a external bootstrap CSS for styling (i.e, manually included `<link type="text/css" ...`) you have plenty of freedom on how to style it.
Reach UI (https://ui.reach.tech), made by Ryan Florence, might be a good start. It has the functionality (and accessibility) for modals, dropdowns, etc., but without heavy styling. I'd been looking for something like it for a long time.
They're like higher-order components on steroids that handle all the heavy lifting of the logic for the component (including what _should_ be rendered) but leave the actual rendering up to you (DOM structure, style, etc).
We're building a very high-level component library ( EditableCard, FormModal, etc. ) at work with Ant Design and mobx. It helps us build our most common UIs very quickly, with very little lines of code, and improvements in one place are then deployed everywhere (like better error handling).
It's still very early / immature but I'd love to hear people's biggest confusions or gripes with it as it exists now:
But I'm confused. I thought one of the main selling points of React was that you use JS but are actually rendering native components (not lookalike ones). Does Ant Design for RN build on native components for each platform, or are they created from scratch (like Flutter)?
I've found Materia-UI to have the best code quality, most up-to-date. If you don't like Material UI theming it's also easily overridable.
Downside of ant-design is that the library is huge (there was a bug recently where the whole icon library was included in the bundle!), some of the components have bugs, style/look is not easily modifiable.
Love ant-design and currently, you can use tree shaking I believe. It is otherwise a heavy lib for sure. Not great for B2C apps, but for B2B with caching it should be okay if users have decent broadband speeds.
Edit: The drag and drop component is nice and looks well-built. I had to use vue-draggable [1] for an app recently which was just a hacky Vue layer on top of Sortable.js [2]. It's one thing I wished ElementUI supported natively.
> drag and drop Lists are notoriously difficult to implement because browsers provide little help when developers have to build drag and drop interactions. Developers using Base Web have the peace of mind that keyboard navigation is reliable and works well with screen readers.
FYI, their drag and drop sample doesn't "work well with screen readers". It's overly verbose and requires keyboard passthrough to operate. So maybe don't take any web designers at their word when they say you can just use their framework and forget about accessibility.
As someone who stopped doing React development before Context became a "thing", is it possible to ELI5 in a couple sentences why it is such an important concept?
It's important, because you don't need to care about props vs state, instead, just consume the context deep in your component tree.
One use case, is, suppose you have two independent contexts at two branches, now, if you want to share those data to 3rd branch, you just create new context with value from the first two contexts.
Contexts in React are like raw pointers in C++. There are reasons to use them, but every time you do, it should raise eyebrows, because they are finicky, complicated to reason about, and thus full of pitfalls.
Yep. That's why context should be used very very rarely or never. When I teach react, I try to make a long detour around them. I would not consider it being the most important concept. Its only a side effect model.
IMO, context does a lot to remove the value of MobX from React applications. Not necessarily Redux; Redux gives you some additional stuff, particularly around state tracking and rewinding. But I haven't seen a MobX project where a judiciously used context doesn't solve the same problem within the React-specific ecosystem.
The value of mobx is that you implicitly link each component to its data dependencies by dereferencing arbitrary paths into your storage objects in the render() function so that the component rerenders only when data at those paths change.
Does the Context achieve this as well? From a quick search, the Context seems to force rerender of any consumer on any change.
React Context is essentially scoped global props (the scope is some subtree of the overall component tree; the props are global to that subtree, any component in the subtree can elect to consume them). Why it's an important concept is that it keeps you from needing to pass props down the tree from each component to its children. This is important because often times those intermediate components don't have any concern with the stuff being passed down, so they shouldn't be concerned with data that doesn't matter to them.
Another way of passing around ~global stuff is Redux, which many people find cumbersome and difficult to understand. And by "many people" I mean me.
I wouldn't go as far as to say Context is the most important concept in React, but it's also not nearly as bad as CSS cascading.
Context is fully opt in. A Context provider upstream will have no observable effect on your downstream components unless you have a component that explicitly chooses to consume _that particular context_.
I think you're thinking of the old Context API where everything merged onto the same shared context object and read from it implicitly. _That_ was a nightmare, hence why it was never recommended for general use, but the new API doesn't suffer from the same issues.
It does force everyone in your organization to not only use React, but also Styletron which might be a pretty large switch for some teams. Has this been a problem?
I think this could lead to limited adoption in some organizations because autonomies teams want to keep delivering with their current stack.
One idea I considered is to have an Atomic CSS library for theme stuff like whitespace, color and typography, and compose those into components for React or Svelte 3 or whatever is hot right now.
All other styling could be done with Styletron, styled components, or plain CSS, whichever suits your team.
Yep. React was adopted a long time ago and it is also now the "industry winner", so no complaining there. Styletron is also older - created more than two years ago.
However, CSS in JS is more controversial and there are some other more popular libraries now. We keep monitoring them and at the same time we are bringing the best features back into Styletron. Also, you could use BaseWeb+Styletron and some other CSS solution for everything else. It's not a big deal (Styletron has like 7kB). But all CSS in JS libs are very similar anyway.
So overall, Base Web was not a big tech switch, React and Styletron have been already widely used.
Referencing and being inspired by someone‘s Design System is a good thing. Try looking at a bunch of them to get a better perspective.
However, using someone's Design System may not always be a good choice. Unless, they are lean, non-directional and are mostly patterns that you can adapt to any tech stack or systems. For instance, Google’s Material Design Philosophy is a good starting point and you can leverage it as your base system. You’ll still need to understand the WHYs of the principles. Without understanding the core principles and the WHYs, you’ll be dependent on it in the wrong fashion.
Here is an example without trying to single it out from the other Design Systems. Sometime back, I studied Ant.Design to see if I can adapt to a massive product overhaul. Unfortunately, I realized that it is a system more specific to the way AliExpress does and think about their design. And technically it was in LESS (CSS Pre-Processor).
There are many good, well thought out systems. One being that of AirBNB’s JavaScript styleguide.
Be inspired, and possibly start with a system that has fewer restrictions, a lot of community activity behind it.
Before even looking at the details ... why would I use this? Uber is not a company that is known for great websites. They get (I'm guessing) 99%+ of their usage through native apps. So why would I believe they're particularly good at building for the web?
It's probably got more engineers behind it than the vast amount of design frameworks, given Uber's size. And some of the components feel pretty nice, so maybe try looking at the details?
Even though most people's primary interaction with Uber is through the native apps, there's a ton of web applications built here. The opening line of the linked article is: "At Uber, we have hundreds of internal web applications" Additionally, there are a number of customer facing web apps from a web version of the rides app to Uber for Business to Uber Freight.
This is why Web Component interest is growing, especially w/ enterprises and large teams. The killer app for WC's is building Design Systems that don't force specific frontend framework decisions.
I've gotten into quite a few debates about this at work and I still don't get why some people are proponents of web components. If you're already a React shop, web components don't seem to be worth the trouble.
1. Web components don't always have the same properties and events as native DOM elements. React provides a ton of conveniences around native elements such as <input> (onChange, defaultValue, className, etc). React even normalizes events across browsers (https://reactjs.org/docs/events.html). If I'm writing a React component that renders a web component, I lose most of those conveniences. The times I've tried using web components at work, I've been bit by issues like web components emitting custom events instead of onclick/onchange/onblur/etc. I've also encountered a web component that was supposed to behave like an input, but element.value didn't return the same thing as element.getAttribute('value').
2. Web components tend to be imperative while React is declarative. That means I have to use a ref to keep a handle on the web component and call functions on it. In many cases, I also have to keep some state in the parent React component to track the web component's internal state.
3. React's lifecycle methods fire when the web component is rendered, not when the web component is "ready". I've had issues where componentDidMount fires, but my ref to the web component doesn't yet have attributes that a normal DOM element would have (such as .value). This makes React's lifecycle methods far less useful and forces me to write guards that aren't necessary with a native DOM element or another React component.
4. It's still not clear to me how web components are supposed to communicate with each other. With React you're either setting state, passing in different props, using context, or using a library like redux (which injects shared state & actions as props). React's solution to this problem is well-structured, understandable, and exposed in React dev tools. With web components, it's still the wild west.
5. Web components accept attributes (which are text only) and slots. React components accept props which can be strings, objects, components, functions, arrays... pretty much anything. If I'm writing a React component that renders a web component, my brain has to switch out of React mode and into web component mode. I get no propTypes validation and I occasionally have to manually translate data between React world and web component world.
In practice I've also encountered issues with development velocity. At work, the team writing web components has taken months to implement basic things such as inputs and callouts. None of their web component code is in production yet. In the same amount of time, a smaller team of devs has used React to build more components and has shipped them to prod.
The overrides system is weird, to say the least. Any consumer can change styles and erbitrary HTML attributes deep inside a component's DOM tree
This breaks encapsulation. As an app developer how do I know my change will be future proof? As a component developer how can I refactor a component or change its behaviour without breaking my consumers?
It feels like stuffing the worst parts of jQuery and old-school CSS back into React.
>CSS-in-JS allows for easy JS-based code-splitting (if you've got that setup) and inlining critical CSS on the page.
All of this can be accomplished without keeping your source of truth in JS config files. SCSS or CSS files can easily be loaded with Webpack and imported into your code. Then you're not giving up the simple yet powerful expressiveness of CSS selectors for a nightmare of nested JS objects.
Generally CSS is loaded into your code where you require them but has to be extracted into a single bundle.
If you want to it truly be loaded into your code where you use it, then CSS-in-JS is the solution and does this for you.
It sounds like the main gripe you have is with syntax, and that's not really required with CSS-in-JS. The 'nightmare of nested js objetcts' can be hidden in the implementation. In fact, many libs (such as emotion) allow you to write CSS syntax using babel macros to preprocess this into javascript.
That's why I love Flow and Typescript so much. They are as opt-in as you want them to be.
I've seen a team use typescript, but have zero types in most of their files, they just used it from libraries to get some IDE autocomplete and some very small typing on core areas.
You're ignoring the fact that many already went through that phase and ultimately decided that complexity is the only enemy worth fighting in software.
It always pays off to take a closer look at the things you can't think or say, to ask why.
> You're ignoring the fact that many already went through that phase and ultimately decided that complexity is the only enemy worth fighting in software.
No, this doesn't match my experience. The people who resist types are usually web designer types who haven't actually worked with type systems at all so they view it as ivory tower nonsense - complexity for complexity's sake.
There is the occasional person who worked with Java in college and hated it, and assumes that every language with types is just a variation on Java. This is, of course, not a very informed position.
Personally, I've worked with both Flow and Typescript, plus Java, C# and Actionscript professionally, and C, C++, D, and Rust for fun (and also Ocaml, SML and Haskell to a lesser degree).
And I still choose to write plain JS sometimes for various reasons. I have many co-workers with several years of work experience who share caution against static typing kool-aid.
Anyone that pits types vs no types as if it's some sort of competition or some elitism thing is probably forgetting to consider that there are in fact perfectly valid scenarios where one is more suitable than the other (and vice versa)
I've been writing code on a daily basis for over 30 years; in umpteen different languages, some more typed than others. And I'm still not very fond of having types shoved down my throat, nor any other kind of restrictions.
We've been building computers and writing code for quite some time now, so long that some of us are beginning to notice the repetitions.
The fact that experience is so often dismissed begins to explain the mess we're in.
Godwin's law strikes again. Static typing is great, don't get me wrong, but it's not always the right solution. There are cases where runtime flexibility can be useful.
TypeScript isn't statically typed, though. I make sure to keep my type boundaries clean but I haven't shied away from dropping into `any` if it was faster to express.
I did then get better at TypeScript over time and remove most of those cases, though.
My only issue is TS usage with extremely large/complex components/containers. For example, files around 500 lines of code, I've temporarily removed TS, done a few other optimizations (ternaries for obvious If/Else statements, etc) to reduce to ~200-230 lines total. The file is instantly easier to reason about and modify.
I wish there was a plugin that just did this automatically so you could toggle it back on when done. To clarify, it's mostly when working with 3rd party/other libs, where you don't have the background of the team.
It's best to leverage type inference if possible. I can point to entire TypeScript files that could be copied and pasted into a JavaScript file and work with no changes.
At some point, yes, you have to use annotations to get the most of it. But, ultimately, I'd much rather trade the additional characters now for the alternative: insanity producing runtime errors in production later.
I agree, it wasn't a good example. More was (attempting) to make a point when inside a complex file, what I've seen. With long interface names mixed in with long variable names, contributing to larger files sizes than necessary. It varies depending on project/company. It's lowercase `boolean`.
This article makes a lot of noise about Uber's commitment to accessibility. So I am led to believe that this new React gizmo is fully accessible.
Yet Uber can't be bothered to make efforts to get basic accessibility right on the page that tells us this.
The main content is not in a <main> element, this <main> element being the landmark that tells people using assistive technologies where the main content is.
Then the navigation links, e.g. in the footer are not in <nav> elements.
The code sample in the middle is an image. It should be in a <figure>, <pre>formatted and in a <code> block for accessibility.
It is a bit hypocritical to write an article about how wonderful your product is for accessibility and not make it accessible.
Those are issues with the CMS being used to host the blog. The blog has been around for a long time and isn't using BaseWeb.
What you're suggesting is that when someone releases a library with a commitment to accessibility, they are also responsible to reach out to some completely unrelated comms-focused team, take over their CMS workflow, rewrite it entirely with the new framework, and only then make a blog post about the thing you were trying to talk about.
Who is "you"? Me personally, the team behind BaseWeb, the comms team, Uber as a whole? Companies by definition can't "care" since they are emotionless entities, so you must mean a physical person. But physical people within a large organization might care about different things with different degrees of priority or be prevented from doing the best thing (tm) for various reasons. But we all already knew that.
No, what I'm saying is that Uber has thousands of engineers and hundreds of web projects, and it's a bit silly to suggest that if one team releases some net positive thing, the cost/time for getting every Uber property to benefit from that thing immediately is zero, and that by not doing such trivial work, Uber is a bad bad dog.
No thanks, Uber. Your community of broscience engineers permanently lost me as a customer after the
Susan Fowler writeup, and I'm not interested in your buggy technology either.
Wait so you are blocking their javascript then claiming it's broken?
I was curious, and I just went in and tried blocking the google analytics, google tag manager, and everything from cdn.jsdelivr.net, and even some random scripts (like the commons.js file), and everything still worked fine as far as I could tell...
It looks pretty nice. My pet peeve with "modern" web design is that it has become, objectively, very effeminate. Uber tends to leans more neutral to slightly masculine.
https://news.ycombinator.com/item?id=18235887
https://element.eleme.io/
https://ant.design/
https://quasar-framework.org/
https://at-ui.github.io/at-ui/
https://developer.microsoft.com/en-us/fabric
https://vmware.github.io/clarity/
http://appnexus.github.io/lucid/
https://ng-lightning.github.io/ng-lightning/
https://blueprintjs.com/
http://www.jetbrains.org/ring-ui/
https://www.lightningdesignsystem.com/
https://elastic.github.io/eui/
https://atlaskit.atlassian.com/