-
Notifications
You must be signed in to change notification settings - Fork 8
Component design conventions
This is a small style guide for writing styles, Typescript, and tests for building PIE web components.
-
We use full class names in modifiers but also nest them. Example:
.foo { &.foo--bar { color: saddlebrown; } }
-
All public methods should have JSDoc comments.
-
All properties in
defs.ts
should have comments. -
Private properties should start with an underscore, such as
private _locale
. -
Default property values should be declared in
defs.ts
. -
Prop types should either be inferred from
defaultProps
or specified using the component’s prop interface:-
Good:
public size = defaultProps.size;
-
Good:
public name: TextInputProps['name'];
-
Bad:
public type: TextInputProps['type'] = defaultProps.type;
-
Bad:
public readonly = false;
-
-
It is unnecessary to add
?
to types inindex.ts
, this should be applied indefs.ts
instead. -
If we know for sure that a
@query
element will exist (i.e., the component is completely useless without it, like thetextarea
element inpie-textarea
), it is acceptable to use!
to tell TypeScript that it will exist. -
Required properties can also use
!
as long as they also use therequiredProperty
decorator. -
All props are destructured into the
render
method (up for discussion). -
Type imports should use the
type
keyword. -
Some lifecycle methods do not need
super
calls (consult Lit docs and consider a linting rule).- Consider a lint rule to enforce
super
calls being the first thing when needed.
- Consider a lint rule to enforce
-
Properties of a string union type (e.g.,
size
,status
,variant
) should use thevalidPropertyValues
decorator. -
Ordering of code in
index.ts
-
Properties first.
-
Lifecycle methods.
-
Other methods
-
Render methods last (except for styles export).
-
-
Use
classMap
for adding conditional (and static) classes to elements. -
Keep logic out of the main render method where possible/practical.
-
Consider splitting the render method into multiple smaller ones, e.g.,
renderLabel
,renderActions
, etc. -
All properties should have a type declaration, e.g.:
@property({ type: String })
-
Component properties should use camelCase naming. For example:
hasBackButton
.- The only exception to this is for properties that are tied to native HTML attributes. For these, we copy the same casing as the native one. For example:
formenctype
andformnovalidate
.
- The only exception to this is for properties that are tied to native HTML attributes. For these, we copy the same casing as the native one. For example:
-
If the property is a boolean value, we aim to prepend the name with
is
. For example:isOpen
,isStrong
.- The only exception to this boolean naming rule is when the property shares a name with a native HTML attribute, such as
disabled
orchecked
.
- The only exception to this boolean naming rule is when the property shares a name with a native HTML attribute, such as
-
Try to avoid type assertions in TypeScript, as it often implies a larger issue in your code:
const foo = bar as string; // avoid this
-
Where a return type is obvious and inferred, there is no need to specify it.
- Do not test for the presence of attributes in templates unless it provides some value. For example, attributes that are conditionally rendered or are important, such as ARIA attributes.