Tokens 🖌️

This page shows some of the design tokens used on this site. Specifically about the colors, I do not define color scales, but I do have some base colors from which I tweak to make custom components like buttons.


There are 6 surfaces ranging from 0 to 5 which denotes how elevated that surface is. Since they do not need to be highly dynamic, they are defined in the tailwind.config.js file. Each surface ( bg-surface-n) is made to be paired with its shadow ( shadow-surface-n).

Surface 1 is the default surface, which is a surface that lies flat on the page, which means it does not have a shadow.



Most colors used on this site is derived from the following base colors. Some hue rotation, saturation and lightness adjusting is done when needed to build a specific component.


As an example, consider the following buttons and the css used to build it.

export const LightButton = ({
  variant = 'primary',
}: Props) => {
  const base = css`
    color: ${getHslaColor(variant, 1, { l: -12 })};

    [data-theme='dark'] & {
      color: ${getHslaColor(variant)};

    background: ${getHslaColor(variant, 0.1)};
    border-color: ${getHslaColor(variant)};
    border-radius: 4rem;

    &:focus {
      background: ${getHslaColor(variant, 0.08)};

  return (
    <button className={cn(base, 'px-4', 'py-2', className)} {...props} />

Other tokens

Other tokens such as text size, spacing, etc. are following tailwindcss tokens.

Reasons for this approach

I initially started working on this site and fully rely on tailwindcss for the styling part. After some time, I started realizing that because I treat my site as a personal playground to try various things, I tend to be very dynamic in making styles. While I can definitely update tailwind configuration to accommodate this use cases, there are problems with that approach.

  1. It's annoying to have to update tailwind.config.js everytime I need to do this
  2. Using tailwindcss, we can support dark mode but not multiple themes at once; this is something I plan to do in the future.
  3. The resulting .css is never codesplitted. This can result in big stylesheet as I add more different styles.

My current approach is to still rely on tailwindcss classes for most basic spacing and layout styles that aren't as dynamic as colors. For colors and other things that might be more dynamic, I derive them on runtime from a set of css variables.

Do note that this is most definitely not the best way to do things, but hey, software engineering is about making tradeoffs. This solution seems to work well enough for me, at least for now. 😄