DESIGN PHASE
Design before you start writing code, design should be fixed/freeze before commence with code (the least for each iteration).
Generate colour palette (e.g. primary/secondary/tertiary/info/warning/alert from shade 100 to 800) before you commence design (which will later be used as colour token in the development phase).
Use OKLab colours as much as possible
Where applicable find a component library that have a similar aesthetics to what you are looking for. (e.g. DaisyUI, FlowBite, Tailwind UI)
Design the website from atom to component, everything should be re-usable component.
All colour and spacing values should come from variable, not hand written values such as RGB(10,20,30) should be found in the component.
Think of all the component, check inspirations from websites such as awwwards.com.
For each component, consider all variants, for instance card can be horizontal or vertical, CTA can have no image (not necessarily cover all the possibilities, but should cover all common conditions on all devices and use cases)
Take the layering of the component into account when designing, for instance header, site-wide notification is always on top of content.
Strict contract of unidirectional spacing ? (instead of applying vertical margin/padding on both side, strictly apply margin/padding only on
margin-block-start/end,padding-block-start/end)
CODE PHASE
Design Pattern & Modularity
**- CSS Level **
- extracting design tokens (and use calc() func)
- e.g. colour token –primary-100
800 –warning-100800- e.g. unit token –margin-sm
xl –padding-smxl - e.g. border-radius –border-radius-field –border-radius-box (see DaisyUI’s border-radius for ref)
- e.g. z-index and shadow (infer from the “layering” decided in design phase, components in the a same layer should have similar z-index and identical shadow)
- e.g. unit token –margin-sm
- extract (small/primitive) reusable component (via @apply)
- e.g. button button-custom{@apply bg-black text-white hover:….}
- e.g. ul/li/ol ul>li{@apply list-disc }
- extract reusable styles (via @apply)
- e.g. remove-container .-container-no-gutter, .-container-with-gutter {@apply -mb-[….]}
- e.g. transition effect .transition-color-300ms-ease {@apply transition-color … }
- e.g. animation effect .animate-load-in {@apply … } **- Component Level **
- e.g. colour token –primary-100
- Component Library
- if you can find a correspondence to the look in the component library, use that instead; Because those components has been maintained by professional team and used by thousands of projects, hence usually have less caveat to worry about
- here are some for your consideration: PinesUI, DaisyUI, FlowBite, TailwindUI
- if you can find a correspondence to the look in the component library, use that instead; Because those components has been maintained by professional team and used by thousands of projects, hence usually have less caveat to worry about
Responsive & Accessibility
- Mobile-First Development
- start with mobile wherever possible
- check against a actual mobile device for the “:active” (when “:hover” is no longer available, what happen when user “press” on element)
- mobile may need shorter animations duration (because on mobile people click instead of hover, though :active can have animation, if the animation is too long, user may not see it before they jump to other pages)
- make responsible work in mobile first, then progressively make it work for tablet and desktop (for instance card)
- Interactivity and A11y
- for all the component that interact with user, for instance change background whenever user hovers, make sure it is also intractable via keyboard navigation, and have its press correspondence on mobile (:active + duration-50)
- **Container Query **
- use container query instead of media query (viewport query), this ensures the component will be responsive when placed in any container; Think about when you place a group of cards in left block of a 7-3 horizontal divided layout.
- consider using container query unit
- Skeleton (Load Animation)
- for slow loading component (e.g. will have bigger image), you can introduce skeleton component to with loading intent animation as soft cushion before the assets/resources finish loading
Configuration
- Tailwind Configuration
- use “prefix” to avoid conflict
- align the “breakpoints” with the bootstrap breakpoint
- declare design token (color/length-unit) where possible
- use @apply to declare reusable component where possible
- Alphine.JS
- use it instead of the bootstrap js libraries to perform data binding and animation
- consider component libraries that uses both, such as PinesUI (https://devdojo.com/pines)
- VS Code Configuration
- use launch.json to run tasks
- Formatter Configuration
- Consider using Prettier to format your code
- you can put your prettier configuration under “prettier” key in “package.json” file, and setup two separate command, one to use “twig” parser to format, one to use “anywhere” as parser, see post: https://blog.simon-hu.org/posts/2025/2025-09-09-format-twig-file-with-prettier/
Miscellaneous
- Site Wide Notification
- consider using cookie (Web Platform APIs) for components such as dismissible site-wide alert, such that the same user can remove it once and no longer see it for the rest of the session.
- UI Suite Ecosystem
- Consider to use UI Suite modules (for non-GovCMS) it is more flexible and intuitive to non-professional user
- Below are the modules under the UI Suite Ecosystem
- Components & Variants with UI Patterns
- Utilities & helpers with UI Styles
- Themes/Modes & CSS Variables with UI Skins
- Icon sets with UI Icons
- Example pages with UI Examples
- **Native CSS Nesting **
- except for the default SaaS/LeeS code that comes with the theme, consider using native CSS nesting for better performance and maintainability, simply create a custom css file and include it in the library that you wish to include globally for the theme
- ONLY override existing style via main/global-override.css, DO NOT TOUCH the default SaaS/LeeS code that comes with the theme, changing it means you will have the use its whole suite of toolkit including the bundling mechanism which may become deprecated one day (e.g. SaaS)
- View Transition API
- fade-in-out / slide-in-out animation when jumping between different pages
- Strict contract of unidirectional spacing ? (instead of applying vertical margin/padding on both side, strictly apply margin/padding only on
margin-block-start/end,padding-block-start/end)