---
name: vue-component-development
description: "Activate when creating or modifying Vue 3 components, pages, layouts, stores, or services in the frontend. Covers component patterns, DaisyUI usage, icon system, toast notifications, drawer patterns, form handling, and the SPA routing/auth flow. Use when working in resources/app/."
license: MIT
metadata:
author: project
---
# Vue Component Development
Patterns and conventions for building Vue 3 frontend components in this project.
## Component Architecture
### Directory Structure
- `views/layouts/` — Layout wrappers (Page, Menu, Auth)
- `views/components/` — Reusable UI components (Button, TextInput, Table, Modal, etc.)
- `views/components/icons/` — Icon system (Icon, Avatar, Spinner)
- `views/components/input/` — Form input components
- `views/components/filters/` — Filter components for list pages
- `views/pages/` — Page-level components organized by auth/private/shared
- `stores/` — Pinia stores (auth, toast, alert, global)
- `services/` — TypeScript API service classes extending BaseService
- `helpers/` — Pure utility functions
### Component Conventions
- Use Options API with `defineComponent()` and `setup()` function (project convention)
- Use `reactive()` for form state, `ref()` for simple values, `computed()` for derived state
- Import components explicitly — no global registration
- Props use camelCase in JS, kebab-case in templates
## UI Framework: DaisyUI 5
This project uses DaisyUI 5 on top of Tailwind CSS 4. Prefer DaisyUI component classes over hand-rolled Tailwind.
### Key classes
- Buttons: `btn btn-primary`, `btn-success`, `btn-error`, `btn-outline`, `btn-ghost`, `btn-sm`
- Inputs: `input input-bordered`, `textarea textarea-bordered`, `select`
- Cards: `card bg-base-100 shadow`, `card-body`, `card-title`
- Tables: `table` with `hover` on `
`
- Badges: `badge badge-success`, `badge-error`, `badge-warning`, `badge-info`
- Alerts: `alert alert-success`, `alert-error`
- Modal: `modal`, `modal-open`, `modal-box`, `modal-backdrop`
- Navigation: `navbar`, `menu`, `breadcrumbs`, `dropdown`
- Loading: `loading loading-spinner`, `skeleton`
- Layout: `drawer`, `drawer-side`, `drawer-content`
### Theme Colors
Use semantic DaisyUI colors, not raw Tailwind colors:
- `primary` (teal), `secondary`, `accent`, `neutral`
- `success`, `warning`, `error`, `info`
- `base-100` (surface), `base-200` (background), `base-300` (border), `base-content` (text)
- Opacity variants: `text-base-content/50`, `border-base-300/50`
### Dark Mode
The project supports light/dark themes via `data-theme` attribute on ``. Both themes use the same teal primary. Custom sidebar colors use `--color-sidebar` / `--color-sidebar-content` CSS variables that adapt per theme. Never hardcode white/black — use semantic DaisyUI colors.
## Icon System
Icons use a thin wrapper around [Heroicons](https://heroicons.com):
```vue
```
To add a new icon: import it in `views/components/icons/Icon.vue` from `@heroicons/vue/24/outline` and add a name→component entry to the `iconMap`.
## Toast Notifications
Use the toast store for user feedback instead of inline alerts:
```js
import {useToastStore} from "@/stores/toast";
const toastStore = useToastStore();
toastStore.success('Done!');
toastStore.error('Failed.');
toastStore.info('FYI...');
toastStore.warning('Careful!');
```
Toasts auto-dismiss after 5 seconds. They accept strings, arrays, or validation error objects.
## Drawer Pattern for CRUD
List pages use a slide-in drawer instead of separate create/edit pages:
- Drawer state: `reactive({ open, mode, loading, form })`
- Open with `drawer.open = true` and set `drawer.mode` to `'create'` or `'edit'`
- Close with `drawer.open = false`, refresh list on success
- Use `` for animation and `` if needed
## API Services
- Services extend `BaseService` or `ModelService` (for CRUD)
- `ModelService` provides: `index()`, `store()`, `update()`, `delete()`, `edit()`, `find()`
- `handleCreate()` and `handleUpdate()` manage loading states and toast notifications
- PUT/PATCH use POST with `_method` field to support FormData file uploads
## Form Handling
- Use `reactive()` for form state
- Use `reduceProperties(form, ['roles'], 'id')` to flatten nested objects before submission
- Use `fillObject(form, data)` to populate form from API response
- Use `clearObject(form)` to reset form