# Install grani by hand

Build a minimal Vue app with Vite, Tailwind CSS and grani. This guide walks through each file without using a starter template.

## 1. Install the packages

```bash
npm i vue grani
npm i -D vite @vitejs/plugin-vue tailwindcss @tailwindcss/vite
```

With another package manager: `pnpm add vue grani && pnpm add -D vite @vitejs/plugin-vue tailwindcss @tailwindcss/vite`, `yarn add vue grani && yarn add -D vite @vitejs/plugin-vue tailwindcss @tailwindcss/vite`, `bun add vue grani && bun add -d vite @vitejs/plugin-vue tailwindcss @tailwindcss/vite`.

## 2. Configure Vite

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [vue(), tailwindcss()],
})
```

## 3. Write the page

Save it as `index.html` in the root of the app.

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My app</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
```

## 4. Start the app

Register grani on your Vue app with `createGrani()`.

```ts
// src/main.ts
import { createApp } from 'vue'
import { createGrani } from 'grani'
import './style.css'
import App from './App.vue'

createApp(App).use(createGrani()).mount('#app')
```

## 5. Import the styles

To customize the theme, add your token overrides below these imports. See [Theming](/guide/theming) for details, or generate brand colors on the [Theme](/theme) page.

```css
/* src/style.css */
@import 'tailwindcss';
@import 'grani/style.css';
```

## 6. Try a form

`UiToaster` displays notifications: mount it once near the root of your app, and `UiConfirm` beside it when you ask questions with `useConfirm()`. Enter a name and select Save: a toast confirms the example is working.

```vue
<!-- src/App.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { UiButton, UiField, UiInput, UiToaster, useToast } from 'grani'

const name = ref('')
const toast = useToast()
function save() {
  toast.success(`${name.value} saved`)
}
</script>

<template>
  <form class="flex flex-col gap-4 p-4" @submit.prevent="save">
    <UiField label="Client name"><UiInput v-model="name" /></UiField>
    <UiButton type="submit" :disabled="!name.trim()">Save</UiButton>
  </form>
  <UiToaster />
</template>
```

## 7. Run it

```bash
npm exec vite
```

With another package manager: `pnpm exec vite`, `yarn vite`, `bunx vite`.

## Optional: auto-import components

Automatically import grani components used in your templates with `GraniResolver`.

```bash
npm i -D unplugin-vue-components
```

With another package manager: `pnpm add -D unplugin-vue-components`, `yarn add -D unplugin-vue-components`, `bun add -d unplugin-vue-components`.

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'
import Components from 'unplugin-vue-components/vite'
import { GraniResolver } from 'grani/resolver'

export default defineConfig({
  plugins: [vue(), tailwindcss(), Components({ resolvers: [GraniResolver()] })],
})
```
