Style Guide
If you wish to contribute to Skeleton, please review our opinionated code style guide below.
General Conventions
Ensure relevant events bubble via event forwarding.
<button on:click on:mouseover>Skeleton</button>
Follow conventions set by existing components when naming slots. These should be short, semantic, and agnostic. Avoid names that are too specific, such as name="icon"
.
{#if $$slots.lead}<slot name="lead" />{/if}
Use caution when inlining Tailwind color classes that would clash with custom themes. Consider using a prop for customization.
❌ <div class="bg-orange-500">Skeleton</div>
✅ <div class="bg-accent-500">Skeleton</div>
If you need to include miscellaneous attributes that were not defined as props, use Svelte's $$restProps
. Be careful though, this can overwrite the element's
$$props.class
attribute. To avoid this, delete the class
key from $$restProps
. The function provided below can handle this on both in it and after any form of attribute updates.
function prunedRestProps(): any {
delete $$restProps.class;
return $$restProps;
}
<button class="... {$$props.class ?? ''}" {...prunedRestProps()}>Skeleton</button>
Property Naming Conventions
Follow these guidelines when creating or adding new component props.
- Each prop should be a single word, all lowercase, and semantic. Match Tailwind class naming conventions whenever possible.
- Color props should follow standard CSS style conventions (ex:
color
for text color). - If you need multiple words, use camel-casing (ex:
ringWidth
). - Never pass class props as arrays or objects. Strings work better (ex:
border border-primary-500
). - Always pass the full Tailwind class name. Tailwind does not support contructed class names.
- Ensure Typescript types are provided and set relevant default values when possible.
- If a new prop is added or modified then please update the documentation. End users need to know this!
Here's a few examples:
export let background: string = 'bg-primary-500'; // background color
export let color: string = 'text-primary-500'; // text color
export let rounded: string = 'rounded-xl'; // border radius
export let visible: boolean = false;
CSS Styling Conventions
Skeleton utilizes a specific paradigm for handling static and dynamic Tailwind styles for components. This is accomplished by passing Tailwind classes to the component as props, as well as by defining base structural classes within the component's script tag. While this may feel odd at first, you will find it works really well in execution.
Base Classes
Any core or structural Tailwind classes can be defined as follows. Note the "c" is short for classes.
let cBase: string = 'bg-surface-500 p-4 rounded'; // parent element styles
let cLabel: string = 'text-base'; // child element label styles
Dynamic Classes
If you expect to set one or more styles based on the current value of a property, handle this within a function as shown below.
// Prop for outlined state
export let outlined: boolean;
// Create a reactive property that uses a ternary statement
$: classesOutlined = outlined ? 'border-2 border-primary-500' : 'border-none';
Reactive Classes
Reactive classes combine all base and dynamic classes. These are applied directly to each respective element.
$: classesTab = `${cBase} ${classesOutlined}`; // parent element
$: classesLabel = `${cBaseLabel}`; // child element
Classes are applied in three ways:
- The first class should be an "identifier" class, providing a selection target for global stylesheet overrides.
- The combined set of reactive class values, which can mix base and dynamic classes.
- For parent elements, add
$$props.classes
to supply additional arbitrary classes.
<div class="tab {classesTab} {$$props.classes ?? ''}">
<span class="tab-label {classesLabel}">Label</span>
</div>
Pitfalls
Below are a few pitfalls we've encountered when creating Skeleton. Do your best to avoid these whenever possible.
- Avoid
style
blocks and@apply
in component files. This can increase the final stylesheet bundle size. - Do not mix script-defined and inline Tailwind classes. Doing so can have a negative impact on the readability of the code.
- Avoid switch-case statements to create shorthand property values (ex: sm, md, lg). This limits customization.
- Keep Skeleton icon library agnostic. Embed SVGs or unicode instead. Consider adding a component slot if an icon is required.