Installation
Install Alixan UI in a Nuxt project. Components are copied directly into your app, so you own the source code and can customize it freely.
Create Project
Start with a Nuxt 4 project. If you already have one, you can skip this step.
npx nuxi@latest init my-appexport default defineNuxtConfig({
app: {
rootId: 'root', // Change appId to root.
},
})Add Tailwind CSS
Alixan UI components use Tailwind CSS classes and CSS variables for the theme.
npm install tailwindcss @tailwindcss/vite -D
@import 'tailwindcss';
@custom-variant dark (&:is(.dark *));
@theme {
/* Set your own font. */
--font-sans: 'Geist', ui-sans-serif, system-ui, sans-serif;
/* Used for Text, Button and etc... */
--text-md: 15px;
/* Default container */
--container-container: 1500px;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 2px);
--color-sidebar-background: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
:root {
--radius: 0.65rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: hsl(0, 0%, 98.5%);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.141 0.005 285.823);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.708 0 0);
--sidebar-background: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.141 0.005 285.823);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(92% 0 0);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.141 0.005 285.823);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--destructive-foreground: oklch(0.985 0 0);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--sidebar-background: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.985 0 0);
--sidebar-primary-foreground: oklch(0.141 0.005 285.823);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.439 0 0);
}
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--border);
}
* {
@apply m-0 p-0 box-border scroll-smooth outline-none;
}
html,
body {
@apply size-full min-h-full bg-background text-foreground overflow-hidden;
}
body {
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
border-radius: 10px;
background: color-mix(in srgb, var(--border) 20%, transparent);
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: color-mix(in srgb, var(--muted-foreground) 20%, transparent);
cursor: grabbing;
}
::-webkit-scrollbar-thumb:hover {
background: color-mix(in srgb, var(--foreground) 40%, transparent);
}
}
#root {
@apply h-full min-h-full w-full flex flex-col divide-y overflow-y-auto;
}
hr {
@apply w-full h-px;
}
button:not(:disabled),
[role='button']:not(:disabled) {
cursor: pointer;
}
p,
span {
color: inherit;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
}
input::-webkit-inner-spin-button,
input::-webkit-outer-spin-button {
-webkit-appearance: none;
}
input[type='search']::-webkit-search-cancel-button {
@apply hidden;
-webkit-appearance: none;
appearance: none;
}
input[type='number'] {
-moz-appearance: textfield;
}
}
/* Used UI blocks. */
@utility island {
@apply flex flex-col border overflow-hidden;
border-radius: clamp(var(--radius-md), 20%, var(--radius-2xl));
}
/* Used for dialog, drawer and overlays. */
@utility backdrop {
@apply fixed inset-0 bg-black/30 dark:bg-black/80;
}
import tailwindcss from '@tailwindcss/vite'
export default defineNuxtConfig({
css: ['~/assets/css/tailwind.css'],
features: {
inlineStyles: true,
},
vite: {
plugins: [tailwindcss()],
},
})Add i18n
Alixan UI works best with Nuxt i18n because documentation labels, table headings and page meta use translation keys. Set missingWarn to false if your app also passes plain values through $t.
npm install @nuxtjs/i18nConfiguration
Use strategy: 'prefix_except_default' to keep the default language without a prefix and prefix all other locales.
For more detailed information, visit the Read the i18n guide for details.
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
vueI18n: './configs/i18n.config.ts',
defaultLocale: 'en',
strategy: 'prefix_except_default',
detectBrowserLanguage: false,
locales: [
{ code: 'en', name: 'English', file: 'en.json' },
{ code: 'ru', name: 'Русский', file: 'ru.json' },
{ code: 'kk', name: 'Қазақша', file: 'kk.json' },
],
},
})Point vueI18n to the external config file and disable i18n warnings in i18n/configs/i18n.config.ts.
export default {
// Disable warnings because some UI props intentionally pass plain strings through $t.
missingWarn: false,
fallbackWarn: false,
}Install Component
Run the CLI from your project root. The component and required utilities will be copied into your project.
npx alixan-ui-nuxt add buttonUse Component
Use the component directly in your Vue templates. No package import is required for the component itself.
<template>
<Button color="primary">
Save changes
</Button>
</template>