SuikunUIPre-Alpha

Installation

Instead of a npm package/library, Suikun UI is a collection of UI components that you can copy-paste and customize into your project. It relies on TailwindCSS and Radix UI.

Pre-requisites

  • TailwindCSS must be installed. You can check out their installation page for the instructions.

Install the dependencies

Add the following dependencies in your project:

npm install tailwind-variants @tabler/icons-react @radix-ui/react-slot

App Structure

My project structure is mostly the following:

  • components - where I put my components.
  • components/ui - where I put my UI components like Button, Input, etc.
  • components/[category] - my components are often organized by category like user, learning-paths, etc.
  • stores - where I put my global state/store. It's either React.Providers, zustand's store or jotai's atoms.
  • pages - route based pages like in NextJS (e.g. About, Home, Profile Pages).
  • lib - where I put all other stuff like api, helper functions, constants values.
.
|- components/
| |- ui/
| | |- Button.tsx
| | |- Input.tsx
| | |- Text.tsx
| |
| |- learning-paths/ (category - based on project)
| | |- PathItem.tsx
| | |- Paths.tsx
| |- user/ (category - based on project)
| | |- UserCard.tsx
| |
| |- OtherComponent.tsx
|
|- lib/
| |- api/
| |- constants/
| |- helpers/
|
|- stores/
|
|- pages/
| |- profile.tsx
| |- about.tsx
| |- index.tsx

Path Aliases (optional)

This is just my preference so you can do you.

NextJS with TypeScript

For my NextJS projects, I update my tsconfig.json:

{
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"@pages/*": ["pages/*"],
"@components/*": ["components/*"],
"@lib/*": ["lib/*"],
"@stores/*": ["stores/*"],
},
},
}

ViteJS

For ViteJS projects, in addition to the tsconfig.json, I also update the vite.config.ts:

import { defineConfig } from 'vite';
import * as path from 'path';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias: [
{ find: '@components', replacement: path.resolve(__dirname, 'src/components') },
{ find: '@pages', replacement: path.resolve(__dirname, 'src/pages') },
{ find: '@stores', replacement: path.resolve(__dirname, 'src/stores') },
{ find: '@lib', replacement: path.resolve(__dirname, 'src/lib') },
],
},
});

Tailwind Configuration

For my tailwind configuration, instead of using the usual colors in TailwindCSS, I use aliases. You can change the following colors:

  • primary
  • secondary
  • warn
  • danger
  • success

Moreover, we need to configure the transformer for the tailwind-variants.

const { withTV } = require('tailwind-variants/transformer');
const colors = require('tailwindcss/colors');
/** @type {import('tailwindcss').Config} */
module.exports = withTV({
darkMode: 'class',
content: [
"./pages/**/*.{js,ts,jsx,tsx,md,mdx}",
"./components/**/*.{js,ts,jsx,tsx,md,mdx}",
],
theme: {
extend: {
colors: {
primary: colors.indigo,
secondary: colors.slate,
warn: colors.amber,
danger: colors.red,
success: colors.emerald,
}
},
},
plugins: [],
});

Styles Configuration

For the styles, I use the following which was inspired by Josh's custom CSS reset:

For Next.js, the root id is #__next and for ViteJS, it's #root. You can change it to whatever you want.

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
* {
margin: 0;
}
*, *::before, *::after {
box-sizing: border-box;
}
html, body, #__next {
height: 100%;
}
#__next {
position: relative;
z-index: 0;
}
#portal {
position: relative;
z-index: 1;
}
body {
line-height: 1.5;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
}

React Portals

For react portals, I include a div for inserting portals:

<div id="portal" />
<div id="root" />