question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Systems: The Core of a Component Library

See original GitHub issue

I’ve been thinking deeply about design systems, specifically component libraries, for a while now. An indicator of a successful library is something that…

Just Works.

Meaning, the person using the library can plop things in and hit the ground running, with minimal configuration, prop “massaging”, and setup.

The components are self-aware. They’re aware of each other. Accessibility, styles, animations, and gestures are built-in by default.

It. Just. Works.

How a library can achieve this workflow is for it to recognize and craft high-quality core systems.

Core Systems Overview

component-system-parts

Above is a rough diagram that illustrates a high-level overview of the various core systems.

These systems would exist at the lowest level of the library. They can be exposed to consumers, however, their interfaces (APIs) should be greatly simplified.


Note: There are even smaller sub-systems in these core systems. For example, Reakit (❤️), uses Popper.js for Popover positioning. Popper.js is a dedicated positioning engine (system).


From a development perspective, I would break it down into 3 levels (lowest to highest)

  1. Core
  2. Library
  3. Consumer

Core

These systems can exist within the project or as 3rd party dependencies, like Reakit (a11y) or Framer Motion (Animation/Gesture). The APIs for working with these parts should be thoughtful and well defined.

If we’re thinking about this from an Atomic Design perspective (in the context of a component library)… These would be electrons, neutrons, and photons (not even atoms!!!)

Library

This is where our components live. I would split these into 2 categories:

  1. Primitives
  2. Non-Primitives (I don’t know what else to call it)

Primitives

Primitives are the base-levels components. In terms of Atomic Design, these are the atoms. The best example of this would be the BaseView or Box component.

Box interfaces directly with the core systems. Beyond that, everything else uses Box.

Other examples of primitives may include:

  • Surface
  • Text

Core system features can be exposed with simplified APIs (aka. component props)

Non-Primitives

Non-Primitives (lol, I need a better name), are elements people most often think about when it comes to Component libraries. These are your Card, Button, TextInput, etc… In terms of Atomic Design, these are the molecules.

They are mostly composed of primitives and work relatively closely with the core systems.

They can be composed together to create larger components (or “molecules”).

For example, a ColorPicker would be composed of many elements, like:

  • TextInput
  • Text
  • Flex
  • Grid
  • Card
  • Popover
  • Button
  • etc…

It may also interface with some of the core systems. (e.g. gestures for dragging).

Consumer

This level exists outside of the library. This is where developers grab our components and build their UIs.

They should be able to compose components together with ease. If needed, they should be able to easily make refinements to styles (style system/theme system) or maybe animation feels (animation system). The APIs for making these adjustments should be incredibly minimal.

Below would be an example of minimal consumer friendly APIs.

Let’s say we want to make something draggable.

Here is react-spring / react-use-gesture:

function PullRelease() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))

  // Set the drag hook and define component movement based on gesture data
  const bind = useDrag(({ down, movement: [mx, my] }) => {
    set({ x: down ? mx : 0, y: down ? my : 0 })
  })

  // Bind it to a component
  return <animated.div {...bind()} style={{ x, y }} />
}

Here is framer-motion

const constraintsRef = useRef(null)
 
return (
  <motion.div ref={constraintsRef}>
    <motion.div
      drag
      dragConstraints={constraintsRef}
    />
  </motion.div>
)

Framer Motion feels much more approachable. It’s easier to read, also, it feels easier to write and modify.

It does a ton of things under-the-hood, but all of that should be taken care of at the core/library level.

It should feel invisible to the consumer.


I understand this may feel a little abstract. To get a (slightly) better sense of things, it may help to explore this repo a bit!

That’s it for now 😃. I’ll add to these notes as I continue my exploration and research ✌️

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
ItsJonQcommented, Aug 27, 2020

Closing this up as we now have a blog to express and share ideas: https://g2components.wordpress.com/

1reaction
diegohazcommented, Jul 21, 2020

Thank you for sharing this! ❤️

I agree with almost everything. I only have two observations:

Framer Motion feels much more approachable. It’s easier to read, also, it feels easier to write and modify.

I agree that Framer Motion looks better, but if I had to choose between Framer Motion and React Spring to use in a component library, I would probably go for the one that has the most flexible API and gives me more control. So, in this case, I would use React Spring internally and maybe expose an API similar to Framer Motion to my consumers.

If we ever need to build something different, Framer Motion may not have a prop that supports it. Whereas with a lower level API like the one React Spring exposes, we have more power over what we can do. But I don’t know Framer Motion enough to discard it. Maybe it exposes some lower level APIs just like Emotion.

These are your Card, Button, TextInput, etc… In terms of Atomic Design, these are the molecules.

Not really important, but I think these components would actually be classified as atoms. Some of them are even mentioned as atoms in the Brad Frost’s Atomic Design blog post.

But the fact that this is confusing and we have to discuss it is just a signal that Atomic Design has failed in structuring design systems, at least when it comes to code. I’ve received a lot of feedback while working on Atomic React, and I could see that the time people were wasting trying to decide whether a component is an atom, molecule or organism wasn’t worth the benefit that the methodology was providing. I tried to remedy it (Do not worry), but it turns out that Atomic Design is another problem. 😅

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to build a component library: a guide for designers
Over the years, there has been much made about the building and maintaining of component libraries (typically referred to as “design systems” by...
Read more >
Component Library
Get to know the AEM Core Components with this collection of component examples - currently featuring a selection of the available components. For...
Read more >
Core components - Design System Checklist
Components are the main building blocks for user interfaces. Building a reusable component library enhances your product development workflow by reducing design ...
Read more >
Core Components Introduction | Adobe Experience Manager
Component Library : A collection of examples to view the components in their various configurations. Component Documentation (this document): ...
Read more >
Rutgers Core Component Library
Units are responsible for securing website developer assistance. Best of all, your Drupal website developer can build on the system to meet your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found