Restructure design system levels
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
With gitlab-org/gitlab-services/design.gitlab.com#2035 (closed) in place it might be the time to start rethinking our current design system structure. This is a proposal to separate current systems into 4 layers with distinct responsibilities and limitations:
- Low level framework
- Pajamas
- GitLab framework
- Application code
Detailed structure
Low level framework
All the low level tooling should fall under this category:
- CSS reset
- Bootstrap
- Tailwind
Rules
This layer must be kept as thin as possible. Boostrap global styles and components should be eventually replaced with Pajamas components.
This code should stay in the design.gitlab.com project.
Pajamas
This includes:
- Pajamas ViewComponents that live in the GitLab main repo right now
- GitLab UI components
- (potentially) Global utility classes outside of Tailwind
Right now these components use gl- class prefix. Eventually it would have to be changed to pj- to reflect the system layer.
ViewComponents could be located right near the Vue counterparts, which makes syncing the changes in between these two systems a breeze. ViewComponent's Lookbook should also be integrated with the support for screenshot regression testing, similar to what we have with Storybook.
Rules
- Can extend/override low level framework
GitLab framework
This includes:
- GitLab-specific overrides of Pajamas components (both Vue and ViewComponents)
- Shared components (currently reside in
javascripts/vue_shared) - GitLab-specific global classes
- GitLab-specific utility classes
This layer allows us to contain any regressions introduced in Pajamas components early on.
We only have to test for GitLab !important to override some of the styles in Pajamas (which we eventually would need to do in some very specific cases).
All the components that override Pajamas should have a storybook with visual regression testing.
For GitLab framework components we could use the gl-fw- prefix, eventually using just gl-.
Rules
- Can override Pajamas and low level framework styles using components
- For Vue components we should define styles in the
<style>block - For ViewComponents we should create styles in the
/framework/components/<component_name>.scssfile
Application code
Everything else that's used to build an application.
For better understanding classes in this layer could also be (potentially) prefixed with app-.
Rules
- No usage of
!important - No Pajamas styling overrides, use GitLab framework for that
- No GitLab framework overrides, create new framework components tailored to the app needs
- Can use low level framework but Pajamas usage is preferable when possible
Why?
Right now all of these systems are scattered across application and have cross-dependencies that are not easy to track and debug:
- ViewComponents use styles from
@gitlab/uipackage but they are located in different projects. It's not easy to test styling changes with this structure. - We rely a lot on
!importantor specificity to override the styles, which makes the whole system incredibly fragile. A slight change in selectors or HTML structure (anywhere in the project, including GitLab UI) can cause for things to break. - It's impossible to know about regressions in advance without manually testing the whole project. This is because we allow to customize GitLab UI components with CSS and this CSS is not scoped to anything or requires complex reproduction steps to actually see the result. We're also not doing visual regression testing in the GitLab main project.
- There's no clear direction where a specific change should go: is it framework? Is it page bundle? The new system should bring an answer to this question.
- Pajamas components couldn't possibly know about all the requirements coming from all the projects that use it, so there must be a way to reliably modify it without causing massive regressions.
Implementation
The implementation will take multiple big steps but all of them are required in order to achieve predictable system that is easy to debug and understand. Regressions will be scoped down and prevented in most cases.
The steps below are a guidance/overview, not exactly how this could/should be implemented.
- Introduce CSS Layers with the following order:
low-level,pajamas,framework. Application layer is not scoped as it simply overrides everything for backwards compatibility.- Scope all the non-application code in a
frameworklayer initially for easier migration - Eventually separate onto dedicated layers
- Layer definition and declaration should happen inside the GitLab main project
- Scope all the non-application code in a
- Separate Pajamas ViewComponents into: Pajamas and GitLab framework components (Pajamas components should not depend on the app)
- Move Pajamas ViewComponents to
design.gitlab.com- Add gem release step, combine it with the general release
- Move all the code overriding
gl-classes to GitLab framework - Create components that override Pajamas component styling (
.gl-fw-badge.gl-badge { /* overrides */ })- For each component a new Storybook/Lookbook story should be created that showcases what is customized
- Replace all the CSS Pajamas overrides with framework components
- Lint against overriding
gl-classes everywhere except framework code (<style>block for Vue component or dedicatedframework/components/stylesheets for ViewComponents)