Technical vision & guidelines โ
Our technical vision describes the goals that we as the development team of onyx want to achieve as well as the boundaries we want to respect when developing onyx.
Legend:
Name | Description | |
---|---|---|
๐ | Rule | Must be followed. Contributions may be rejected otherwise |
๐ฎ | Vision | Our long-term goal for onyx |
Global Architecture โ
- ๐ onyx does not have direct dependencies, only a limited amount of peer- and dev-dependencies.
- peer-dependencies: we allow a wide range of versions (e.g.
>= 3
). - We use third-party dependencies sparingly. The need for each dependency must be well justified and documented in this wiki.
- peer-dependencies: we allow a wide range of versions (e.g.
- ๐ We rely on browser / native features as much as possible. We accept some drawbacks this decision might bring.
- ๐ Frequently used code is extracted into utils / composables.
- ๐ฎ We provide custom eslint rules for principles and best practices where needed.
Release process โ
- ๐ฎ All packages use one of two release channels:
beta
: automatically released on each merge to themain
branchdefault
/prod
: released after the current sprint has ended. Requires manual approval.
Pull Requests โ
- ๐ Every PR that affects the public API of any published npm libraries must include a changeset.
- ๐ A PR must consist of one (preferable) or multiple self-contained changes.
- ๐ An "Implement" ticket can and will usually be split up over multiple PRs, so a single PR doesn't have to include all feature facets.
- โ๏ธ These PRs should be sliced reasonably, as a set of changes that belong together.
- This enables us to do faster Code Reviews.
Documentation โ
- ๐ Everything we publish (features, packages, ...) must be documented
- ๐ The documentation explains everything the users need to know and do not expect implicit knowledge. E.g. all variants that a component offers are showcased and explained when they are used
- ๐ฎ We provide an overview page which shows previews of all of our components on one page
- ๐ฎ We have a well understandable changelog which includes all relevant information on the usage of the changes
- ๐ฎ Our documentation supports fuzzy/keyword searchย for finding components
Usability โ
- ๐ The DX (Developer Experience) of our users is our top priority
- ๐ We only support modern technologies (ES202x)
- ๐ onyx components work in all of the three big browsers: Chromium, Firefox and Safari
- ๐ We offer excellent typing support
- ๐ฎ We only use Web APIs that have a "Can I Use" score of > X%
Component Interface โ
- ๐ One use case is covered by only one (public) component
- e.g. there is only one table component instead of a "basic" and "advanced" table
- ๐ Component variants that differ in regards to their aria pattern are separate components
- ๐ Whether we prefer a property vs. slot based API for a component feature will be decided on a case-by-case-basis
- ๐ When Prop/Attr names of the (wrapped) native element are being used for component properties,
- they must mirror the expected behavior of the native attribute
- they may limit the natives attribute accepted values (e.g.
type
property of the input could be limited to only support typetext
andpassword
)
- ๐ Fallthrough attributes should be passed to the most sensible native element of the component.
- fallthrough attributes must not be part of the documented or recommended API
- ๐ All boolean properties default to
undefined
(falsy) - ๐ We prevent complex conditions due to big union modelValue types.
- We either offer specialized components (e.g. separating a number input from a text input)
- Alternatively, we can make use of generic components
- ๐ Components are shipped as native Vue components, not as Web Components
- ๐ฎ We provide translations for standard texts inside components, e.g. "OK", "Cancel" etc. and allow to override them.
- Community contributions to our translations are most welcome!
- ๐ฎ We support common navigation patterns, e.g. keyboard shortcuts
- ๐ฎ The implemented components reflect the capabilities of Figma
- Exception: We can't limit what will be passed into a slot
- Exception: We use number and other property types that can not be declared in Figma
- ๐ฎ We use a shared domain language between UX and DEV
- e.g. for component names, variable names, ...
- ๐ฎ All components can be used standalone in a project without affecting styles of the whole application (so they can be used together with other component libraries). Therefore, we provide two CSS files:
- Component styles: Required. Defines the styles of the components, no side effects on globals
- Global styles: Optional. Applies global styles to the whole application (e.g. color / background color on
body
,<a>
etc.)
Alternatively, a layout component (e.g. OnyxSpace) might be provided for this.
Naming conventions โ
- ๐ All (public) components are prefixed with
Onyx
, e.g.OnyxButton
- ๐ We use v-model for two-way-data-binding wherever possible
- ๐ Component variants are named after what they are, not where they are used (e.g. a link variant "fullWidth" instead of "sideBar")
- ๐ Event names won't get an
onyx
prefix - ๐ Boolean properties are prefixed with
is-
orhas-
. Exceptions are made to align with default html properties, e.g.required
- ๐ All CSS class names are prefixed with
onyx-
- ๐ All CSS variables are prefixed with
--onyx-
Component Implementation โ
- ๐ A component renders only visible content (e.g.
v-if
instead ofdisplay: none;
) - ๐ We don't clone DOM nodes. Instead, we can place slots in different places depending on the breakpoint
- ๐ We only use as much JavaScript as necessary (e.g. prefer CSS over JavaScript)
- ๐ Property types are declared and exported as standalone type and referenced in the
defineProps
- the property type can still be declared (and exported) inside the component file to which it belongs
- ๐ We always use the notation
props.foo
instead of accessingfoo
directly in the<template>
section - ๐ We structure the component code in the following manner:
- types / props / emits
- composables
- refs
- computed / functions
- watchers
A11y (Accessibility) โ
- ๐ We use semantic HTML
- ๐ We keep the DOM tree as flat as possible
- ๐ We follow A11y best practices (level AA)
- ๐ We define aria relevant attributes as required
- e.g. an image component would have a required
alt
property - We offer an alternative
inaccessible
orno-a11y
property, e.g. for declaring decorative images
- e.g. an image component would have a required
Typescript โ
- ๐ We use types instead of interfaces and enums
- ๐ We use strict undefined/null checks when implementing the onyx ecosystem
- ๐ We prefer maps over enums
CSS โ
- ๐ Instead of using
scoped
/module
for<style>
, we rely on meaningful class structures- we use BEM to provide semantic and structured class names
- all styles related to a component are bundled inside one component class, e.g. the component
OnyxInput
has one classonyx-input
which groups all styles of that component
- ๐ We don't use
!important
- ๐ We define only as little style as needed
- Instead of copying Figma styles, we evaluate what is needed
- ๐ Component styles are limited to the component internals
- We don't set opinionated margins on the components that define how they are spaced in the page layout.
- ๐ We use
flex
for 1 dimensional layouts andgrid
for 2 dimensional layouts - ๐ We avoid writing styles on a parent component that are applied to children that are placed in a slot
- Exception: When the alternative would over-complicate the interface, e.g. by requiring extra properties
- ๐ We prefer pseudo-classes over class names we set ourselves
- ๐ We prefer styles that don't rely on
:not()
- ๐ We can use
::before
and::after
for styling - ๐ We use
rem
for everything. This includes borders, font-sizes, ... - ๐ We don't infer the device type by the window width
Testing โ
- ๐ Each (public) component is covered by at least 1 screenshot test (via Playwright)
- ๐ All defined component behavior is covered by a playwright test (
.ct.tsx
file) - ๐ Utils and composables are covered by Vitest tests (
.spec.ts
file) - ๐ We structure our tests by using the arrange-act-assert patternts
// ARRANGE // ACT // ASSERT
Things the future might hold โ
The following points might be discussed when their use-case gets more concrete.
- Offer package with test-utils
- Measure the performance of components which contain a lot of content
- We provide SSR support / compatibility
- We use progressive enhancement where possible