Atomium Design System
repository·main·Indexed 41 days ago
https://github.com/juntossomosmais/atomiumThe official design system of Juntos Somos Mais, built with Web Components to provide reusable UI elements across React, Vue, and Vanilla JS. It includes a core component library, a dedicated icon system served via CDN, and a set of design tokens available as CSS variables, JavaScript objects, or JSON.
What's inside Atomium
- Atomium's Vue components are not manually written; they are automatically generated from Atomium's core Web Components using Stencil's Vue output target. This ensures that the Vue components maintain full compatibility with the underlying Web Component logic while providing a native Vue developer experience.
Understand Elevation tokens
mainElevation tokens in the Juntos Design System indicate the distance of interface elements from the surface, determining how their shadows appear. The system provides 8 elevation levels (0dp to 8dp). To achieve a natural shadow effect, each token utilizes overlapping shadows.
Additionally, the system provides
zindextokens to manage the stacking order of elements, which should be used in conjunction with elevation to maintain visual hierarchy.Why Atomium uses Web Components
mainAtomium is built using Web Components to ensure the design system remains highly portable and future-proof. This architectural choice addresses several key requirements for modern development:
- Framework Agnostic: Components can be used seamlessly in React, Vue, Angular, or any other framework.
- Platform & Device Agnostic: They are compatible across web, mobile, and desktop platforms and various device types (desktops, tablets, phones).
- Reusability: The standard-based approach allows for high reusability across different projects.
- Browser Compatibility: Web Components enjoy broad support across all modern browsers (Chrome, Firefox, Safari, Edge).
- Standardization: As a W3C standard, Web Components provide long-term viability and allow for extending HTML with encapsulated styling and custom behavior.
Why Atomium provides transpiled wrappers for React and Vue
mainAtomium uses transpiled wrappers for both React and Vue to solve inherent compatibility issues between Web Components and these frameworks.
Without these wrappers, developers face several Developer Experience (DX) hurdles:
React Challenges
- Event Handling: React uses
SyntheticEvent, which is incompatible with theCustomEventinterface used by Web Components. Developers would otherwise need to manually attach event listeners. - Data Types: Props containing
arrayorobjecttypes often require manual conversion to JSON strings to ensure compatibility with the Web Component's attributes. - API Access: Accessing the underlying Web Component API requires using
ref. - Complexity: Effective usage often requires manual creation of custom wrappers.
Vue Challenges
- Data Types: Similar to React,
arrayandobjectprops require manual JSON conversion. - API Access: Accessing the Web Component API requires using
ref.
The Solution
Atomium provides specialized packages (
@juntossomosmais/atomium-reactand@juntossomosmais/atomium-vue) that act as transpiled wrappers. These packages ensure seamless integration, proper event handling, and correct prop type passing, providing a native-like DX for both frameworks.- Event Handling: React uses
How Atomium React components are generated
mainAtomium's React components are not manually written; they are automatically generated from Atomium's core Web Components using Stencil's React output target. This ensures that the React components provide a native React experience (including props and event handling) while wrapping the underlying high-performance Web Components.Identify Atomium screen breakpoints and ranges
mainAtomium defines specific breakpoints used across projects to manage responsive layouts. Use these ranges to understand how the design adapts to different device sizes:
- Extra Small: 0 - 575px
- Small: 576px - 767px
- Medium: 768px - 991px
- Large: 992px - 1199px
- Extra Large: >= 1200px
Server-safe component development patterns
mainWhen developing or extending Atomium components, be aware that lifecycle hooks (
connectedCallback,componentWillLoad,componentDidLoad,render) execute during server hydration. To prevent crashes in Node environments, follow these patterns:- Avoid direct
windowordocumentaccess: Use fallbacks for APIs likematchMediawhich may not exist in the Node global scope. - Guard layout-dependent code: Code that relies on browser-only APIs (like
getComputedStyleor Popper.js instances) must be guarded. - Use the correct guard pattern: Use
Build.isServer && !Build.isTestingrather than justBuild.isServer. This ensures that while the code is skipped during SSR, it remains executable during Jest unit tests (whereisServerandisTestingare both true).
Example Guard Pattern:
if (Build.isServer && !Build.isTesting) { // Skip server-only logic or browser-only initialization }- Avoid direct
Understand the Component Encapsulation Strategy for SSR
mainAtomium uses two different encapsulation strategies for Web Components to ensure they work correctly during Server-Side Rendering (SSR) and client-side hydration, specifically when used in frameworks like React (Next.js).
1. Interactive In-flow Components (
shadow: true)Components that require immediate interactivity and data propagation (like
atom-input) use Shadow DOM (shadow: true).- Why: These components are emitted as Declarative Shadow DOM (
<template shadowrootmode="open">). This allows the Stencil runtime to hydrate them reliably even when they are nested inside other Stencil components during SSR. - Use case: Inputs, text fields, and any component where value propagation and validation must work immediately after hydration.
2. Overlay and Teleporting Components (
scoped/light DOM)Components that render overlays (like
atom-modal,atom-datetime, andatom-steps-modal) use Scoped/Light DOM encapsulation and are excluded from SSR.- Why: These components rely on Ionic's teleportation mechanism (moving content to
bodyorion-app). In Shadow DOM,<slot>is a virtual projection; if the slot element teleports away, the projected content disappears. Using light DOM ensures content travels with the teleported element. - SSR Behavior: These components are rendered client-only. They will not be present in the initial server-rendered HTML, but they will mount correctly on the client. This avoids the "inert" problem where scoped components nested in other components fail to hydrate.
Summary Table
Component Type Encapsulation SSR Strategy Example In-flow Interactive shadow: trueFull SSR (DSD) atom-inputOverlays/Teleports scopedClient-only atom-modal,atom-datetimeImplementation Note for React/Next.js Users
To ensure you inherit this encapsulation logic correctly, always consume the package via the
@juntossomosmais/atomium/react/nextbarrel entry. This entry point automatically resolves overlays to their client-only versions.- Why: These components are emitted as Declarative Shadow DOM (
How Atomium Icons work
mainAtomium uses a wrapper for Ionic Components (available in the
@atomium/corepackage) to manage icons. This wrapper leverages Ionic's logic to fetch icon SVGs from a CDN and render them within the Shadow DOM.This architecture provides two main benefits:
- Reduced bundle size: Icons are not bundled with your application code, optimizing performance.
- Cross-platform compatibility: The same icons can be used across any framework (React, Vue, Angular, Svelte, etc.) because they are served via a central CDN.
How Atomium SSR Hydration works
mainAtomium uses a
hydrateModule(exported from@juntossomosmais/atomium/hydrate) to enable Server-Side Rendering.When
renderToString()is called in a Node environment, the library serializes components using Declarative Shadow DOM (DSD). This means the server returns HTML containing<template shadowrootmode="open">tags. This allows the browser to render the component's shadow DOM immediately upon receiving the HTML, before the client-side JavaScript has even loaded, effectively eliminating FOUC and layout shifts.Because Atomium includes
@ionic/coreinternals, even Ionic components (ion-*) inside Atomium shadow roots are fully rendered on the server with their styles and modes resolved.Understand the color contrast contract
mainAtomium contextual colors follow a strict WCAG 2.1 AA contrast contract to ensure accessibility. Each color step has a specific intended use case:
-dark-1: High emphasis. At least 7:1 against white. Use for emphasis, hover, and pressed states.-regular: The default step. At least 4.5:1 against white AND at least 4.5:1 against its own-light-2. Use for text, icons, borders, or as a fill with white text.-light-1: The light step. At least 4.5:1 as a fill carrying dark text, AND at least 4.5:1 as text/icon on a dark surface. Use on dark surfaces.-light-2: The soft surface. Use as a background, not as a foreground color.
Recommendation: Use
-regularby default for ordinary text, icons, or borders. Only use-dark-1when higher emphasis is required.How Atomium React wrappers work
mainAtomium React components are automatically generated wrappers around core Web Components using
@stencil/react-output-target. This architecture ensures:- Seamless integration between Web Components and React.
- Proper TypeScript types and interfaces for all components.
- Correct handling of React synthetic events.
- Seamless management of props, refs, and lifecycle methods.