https://news.ycombinator.com/item?id=18235887
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/
http://www.jetbrains.org/ring-ui/
https://www.lightningdesignsystem.com/
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.
No real intent there. It's good to have large organizations donating libraries to open-source.
Google's https://material.io/design/
I guess most companies have a design system in place
If you want style guides and design systems then the link by "oedmarap" is much better.
https://www.quora.com/What-CSS-framework-does-Twitter-use-in...
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.
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.
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.
[0] https://twitter.com/olivtassinari/status/1120818781058686979
Context is the most important concept in React.
Actually, a library just need users to provide the right types of Context to be flexible.
I'm tired of the "lock in" API, in which, it doesn't allow me to just get my context data into its arguments API.
In this sense, you can consider Context as the local version of Redux.
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.
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.
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.
Then in all components props, you'll have your own context value at every level deep in the tree.
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.
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.
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".
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.
Settled on ant.design for a while, not perfect but good enough.
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)?
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.
Edit: It does use Flow.
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.
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.
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.
togglePanel = (newTogglePanelComponentState: Boolean) => {
return this.setState({ panelToggleState: newTogglePanelComponentState });
}
togglePanel = bool => this.setState({ panelToggle: bool })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.
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.
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.
Some things you either have or you don't. Accessibility is one of those things. Either you think it is actually important or you don't.
The Uber comms team also need to be living and breathing accessibility. It is part of what comms is about.
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.
Any recommendations?
How to reproduce:
1. Visit the official website https://baseweb.design/
2. Click "Welcome" on the sidebar.
3. "An unexpected error has occurred."
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.
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).
There’s already a way to overwrite props in react. Just use props.
If you need to expose the native API of the underlying element, do this (does HN format code?)...
``` const {foo, ...native} = props;
<label {...native}> <p>{foo}</p> </label>
```
Combine that with default props and you’re good to go.
There’s already a way to allow components to take multiple types of children.
``` <Select render={ blah => { return <CustomOption>{blah}</CustomOption> }} /> ```
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.
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.
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.
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.
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.
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.
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.