---
metaTitle: Component Cookbook | AwesCode UI
meta:
  - name: description
    content: Common UI patterns and recipes using AwesCode UI components - real-world examples for building applications.
title: Component Cookbook
---

# Component Cookbook

Real-world patterns and recipes for common UI scenarios.

## Table of Contents

- [Authentication](#authentication)
- [Data Tables](#data-tables)
- [User Profiles](#user-profiles)
- [Dashboards](#dashboards)
- [Lists & Cards](#lists--cards)
- [Navigation](#navigation)
- [Notifications](#notifications)
- [Modals & Dialogs](#modals--dialogs)

## Authentication

### Login Page

```markup
<template>
  <AwCard class="max-w-md mx-auto">
    <template #title>
      <AwHeadline>Sign In</AwHeadline>
    </template>

    <form @submit.prevent="onLogin">
      <AwGrid>
        <AwInput
          v-model="formData.email"
          name="email"
          label="Email"
          type="email"
          required
          autofocus
        />

        <AwPassword
          v-model="formData.password"
          name="password"
          label="Password"
          required
        />

        <AwFlow justify="between" align="center">
          <AwCheckbox v-model="formData.remember" label="Remember me" />
          <AwLink href="/forgot-password">Forgot password?</AwLink>
        </AwFlow>

        <AwButton type="submit" size="lg" class="w-full">
          Sign In
        </AwButton>
      </AwGrid>
    </form>

    <AwDescription tag="div" class="text-center mt-4">
      Don't have an account?
      <AwLink href="/register">Sign up</AwLink>
    </AwDescription>
  </AwCard>
</template>

<script>
export default {
  layout: 'center',

  data() {
    return {
      formData: {
        email: '',
        password: '',
        remember: true
      }
    }
  },

  methods: {
    onLogin() {
      this.$notify({
        title: 'Login successful',
        type: 'success'
      })
      this.$router.push('/dashboard')
    }
  }
}
</script>
```

### Registration Form

```markup
<template>
  <AwCard class="max-w-lg mx-auto">
    <template #title>
      <AwHeadline>Create Account</AwHeadline>
    </template>

    <form @submit.prevent="onRegister">
      <AwGrid>
        <AwGrid :cols="2" :gap="4">
          <AwInput
            v-model="formData.first_name"
            name="first_name"
            label="First Name"
            required
          />
          <AwInput
            v-model="formData.last_name"
            name="last_name"
            label="Last Name"
            required
          />
        </AwGrid>

        <AwInput
          v-model="formData.email"
          name="email"
          label="Email"
          type="email"
          required
        />

        <AwPassword
          v-model="formData.password"
          name="password"
          label="Password"
          required
          minlength="8"
        />

        <AwPassword
          v-model="formData.password_confirmation"
          name="password_confirmation"
          label="Confirm Password"
          required
        />

        <AwCheckbox v-model="formData.terms" label="I agree to the Terms of Service" required />

        <AwButton type="submit" size="lg" class="w-full">
          Create Account
        </AwButton>
      </AwGrid>
    </form>

    <AwDescription tag="div" class="text-center mt-4">
      Already have an account?
      <AwLink href="/login">Sign in</AwLink>
    </AwDescription>
  </AwCard>
</template>

<script>
export default {
  layout: 'center',

  data() {
    return {
      formData: {
        first_name: '',
        last_name: '',
        email: '',
        password: '',
        password_confirmation: '',
        terms: false
      }
    }
  },

  methods: {
    onRegister() {
      this.$notify({
        title: 'Account created successfully',
        type: 'success'
      })
      this.$router.push('/dashboard')
    }
  }
}
</script>
```

## Data Tables

### User List with Actions

```markup
<template>
  <AwPage title="Users">
    <template #buttons>
      <AwButton href="/users/create" icon="plus">
        Add User
      </AwButton>
    </template>

    <AwTableBuilder
      :url="'/api/users'"
      :columns="columns"
      :filters="filters"
    >
      <template #cell(name)="{ row }">
        <AwFlow align="center" :gap="2">
          <AwUserpic :src="row.avatar" :name="row.name" />
          <div>
            <div class="font-medium">{{ row.name }}</div>
            <div class="text-sm text-gray-500">{{ row.email }}</div>
          </div>
        </AwFlow>
      </template>

      <template #cell(role)="{ value }">
        <AwBadge :color="getRoleColor(value)">
          {{ value }}
        </AwBadge>
      </template>

      <template #cell(status)="{ value }">
        <AwBadge :color="value === 'active' ? 'success' : 'mono'">
          {{ value }}
        </AwBadge>
      </template>

      <template #cell(actions)="{ row }">
        <AwContextMenu>
          <AwDropdownButton
            icon="edit"
            :href="`/users/${row.id}/edit`"
          >
            Edit
          </AwDropdownButton>
          <AwDropdownButton
            icon="trash"
            @click="deleteUser(row.id)"
          >
            Delete
          </AwDropdownButton>
        </AwContextMenu>
      </template>
    </AwTableBuilder>
  </AwPage>
</template>

<script>
export default {
  data() {
    return {
      columns: [
        { name: 'name', label: 'User', sortable: true },
        { name: 'role', label: 'Role', sortable: true },
        { name: 'status', label: 'Status', sortable: true },
        { name: 'created_at', label: 'Joined', sortable: true },
        { name: 'actions', label: '', align: 'right' }
      ],
      filters: [
        { name: 'role', component: 'AwSelect', options: ['Admin', 'User'] },
        { name: 'status', component: 'AwSelect', options: ['Active', 'Inactive'] }
      ]
    }
  },

  methods: {
    getRoleColor(role) {
      const colors = {
        'Admin': 'error',
        'Editor': 'accent',
        'User': 'mono'
      }
      return colors[role] || 'mono'
    },

    async deleteUser(id) {
      if (confirm('Are you sure?')) {
        await this.$axios.delete(`/api/users/${id}`)
        this.$refs.table.refresh()
      }
    }
  }
}
</script>
```

### Sortable & Filterable Table

```markup
<template>
  <AwCard>
    <template #title>
      <AwFlow justify="between" align="center">
        <AwHeadline>Products</AwHeadline>
        <AwSearch v-model="search" placeholder="Search products..." />
      </AwFlow>
    </template>

    <AwTable
      :data="filteredProducts"
      :columns="columns"
      @sort="onSort"
    >
      <template #cell(image)="{ row }">
        <img :src="row.image" :alt="row.name" class="w-12 h-12 object-cover rounded" />
      </template>

      <template #cell(price)="{ value }">
        ${{ value.toFixed(2) }}
      </template>

      <template #cell(stock)="{ value }">
        <AwLabel :color="value > 10 ? 'success' : 'error'">
          {{ value }} in stock
        </AwLabel>
      </template>
    </AwTable>

    <AwPagination
      v-model="currentPage"
      :total="totalPages"
    />
  </AwCard>
</template>
```

## User Profiles

### Profile View

```markup
<template>
  <AwPage :title="user.name">
    <template #buttons>
      <AwButton :href="`/users/${user.id}/edit`" icon="edit">
        Edit Profile
      </AwButton>
    </template>

    <AwGrid :cols="{ default: 1, lg: 3 }" :gap="6">
      <!-- Profile Info -->
      <div class="lg:col-span-1">
        <AwCard>
          <AwFlow direction="column" align="center" :gap="4">
            <AwUserpic
              :src="user.avatar"
              :name="user.name"
              size="xl"
            />

            <div class="text-center">
              <div class="text-xl font-bold">{{ user.name }}</div>
              <div class="text-gray-500">{{ user.email }}</div>
            </div>

            <AwBadge :color="user.status === 'active' ? 'success' : 'mono'">
              {{ user.status }}
            </AwBadge>
          </AwFlow>
        </AwCard>

        <AwCard title="Details" class="mt-4">
          <AwList>
            <li>
              <AwIcon name="briefcase" />
              <span>{{ user.role }}</span>
            </li>
            <li>
              <AwIcon name="calendar" />
              <span>Joined {{ user.created_at }}</span>
            </li>
            <li>
              <AwIcon name="map-marker" />
              <span>{{ user.location }}</span>
            </li>
          </AwList>
        </AwCard>
      </div>

      <!-- Activity -->
      <div class="lg:col-span-2">
        <AwTabNav
          v-model="activeTab"
          :items="[
            { value: 'activity', text: 'Activity' },
            { value: 'posts', text: 'Posts' },
            { value: 'settings', text: 'Settings' }
          ]"
        />

        <div v-show="activeTab === 'activity'" class="mt-4">
          <ActivityFeed :user-id="user.id" />
        </div>

        <div v-show="activeTab === 'posts'" class="mt-4">
          <UserPosts :user-id="user.id" />
        </div>

        <div v-show="activeTab === 'settings'" class="mt-4">
          <ProfileSettings :user="user" />
        </div>
      </div>
    </AwGrid>
  </AwPage>
</template>
```

### Profile Edit

```markup
<template>
  <AwPageSingle
    title="Edit Profile"
    :breadcrumb="{ href: '/profile' }"
    :action="{ text: 'Save Changes', color: 'accent' }"
    @action="saveProfile"
  >
    <AwForm ref="form" url="/api/profile" method="patch" @sended="onSaved">
      <AwCard title="Personal Information">
        <AwGrid :cols="2" :gap="4">
          <AwInput v-model="user.first_name" name="first_name" label="First Name" />
          <AwInput v-model="user.last_name" name="last_name" label="Last Name" />
        </AwGrid>

        <AwInput v-model="user.email" name="email" label="Email" type="email" />

        <AwTextarea v-model="user.bio" name="bio" label="Bio" rows="4" />
      </AwCard>

      <AwCard title="Profile Picture" class="mt-4">
        <AwCropper
          v-model="user.avatar"
          name="avatar"
          :aspect-ratio="1"
        />
      </AwCard>

      <AwCard title="Contact Information" class="mt-4">
        <AwTel v-model="user.phone" name="phone" label="Phone" />
        <AwAddress v-model="user.address" name="address" label="Address" />
      </AwCard>
    </AwForm>
  </AwPageSingle>
</template>

<script>
export default {
  data() {
    return {
      user: {}
    }
  },

  async mounted() {
    const { data } = await this.$axios.get('/api/profile')
    this.user = data
  },

  methods: {
    saveProfile() {
      this.$refs.form.$el.submit()
    },

    onSaved() {
      this.$notify({ title: 'Profile updated successfully!' })
      this.$router.push('/profile')
    }
  }
}
</script>
```

## Dashboards

### Admin Dashboard

```markup
<template>
  <AwPage title="Dashboard">
    <!-- Stats -->
    <AwGrid :cols="{ default: 1, sm: 2, lg: 4 }" :gap="4">
      <AwCard>
        <AwFlow align="center" justify="between">
          <div>
            <AwDescription>Total Users</AwDescription>
            <div class="text-3xl font-bold">{{ stats.users }}</div>
          </div>
          <AwIcon name="users" class="text-4xl text-accent" />
        </AwFlow>
      </AwCard>

      <AwCard>
        <AwFlow align="center" justify="between">
          <div>
            <AwDescription>Revenue</AwDescription>
            <div class="text-3xl font-bold">${{ stats.revenue }}</div>
          </div>
          <AwIcon name="dollar" class="text-4xl text-success" />
        </AwFlow>
      </AwCard>

      <AwCard>
        <AwFlow align="center" justify="between">
          <div>
            <AwDescription>Orders</AwDescription>
            <div class="text-3xl font-bold">{{ stats.orders }}</div>
          </div>
          <AwIcon name="shopping-cart" class="text-4xl text-info" />
        </AwFlow>
      </AwCard>

      <AwCard>
        <AwFlow align="center" justify="between">
          <div>
            <AwDescription>Growth</AwDescription>
            <div class="text-3xl font-bold">+{{ stats.growth }}%</div>
          </div>
          <AwIcon name="trending-up" class="text-4xl text-success" />
        </AwFlow>
      </AwCard>
    </AwGrid>

    <!-- Charts -->
    <AwGrid :cols="{ default: 1, lg: 2 }" :gap="4" class="mt-6">
      <AwCard title="Revenue Over Time">
        <AwChart :data="revenueData" type="line" />
      </AwCard>

      <AwCard title="User Growth">
        <AwChart :data="userGrowthData" type="bar" />
      </AwCard>
    </AwGrid>

    <!-- Recent Activity -->
    <AwCard title="Recent Orders" class="mt-6">
      <AwTable :data="recentOrders" :columns="orderColumns" />
    </AwCard>
  </AwPage>
</template>
```

## Lists & Cards

### Product Grid

```markup
<template>
  <AwPage title="Products">
    <template #buttons>
      <AwButton href="/products/create" icon="plus">
        Add Product
      </AwButton>
    </template>

    <AwGrid :cols="{ default: 1, sm: 2, lg: 3, xl: 4 }" :gap="4">
      <AwCard v-for="product in products" :key="product.id">
        <img
          :src="product.image"
          :alt="product.name"
          class="w-full h-48 object-cover rounded-t"
        />

        <template #title>
          {{ product.name }}
        </template>

        <AwDescription>{{ product.description }}</AwDescription>

        <AwFlow justify="between" align="center" class="mt-4">
          <div class="text-2xl font-bold">${{ product.price }}</div>
          <AwButton size="sm" :href="`/products/${product.id}`">
            View
          </AwButton>
        </AwFlow>

        <template #footer>
          <AwBadge :color="product.inStock ? 'success' : 'error'">
            {{ product.inStock ? 'In Stock' : 'Out of Stock' }}
          </AwBadge>
        </template>
      </AwCard>
    </AwGrid>

    <AwPagination
      v-model="page"
      :total="totalPages"
      class="mt-6"
    />
  </AwPage>
</template>
```

### Timeline View

```markup
<template>
  <AwCard title="Activity Timeline">
    <AwTimelineBuilder :items="activities">
      <template #item="{ item }">
        <AwFlow :gap="3">
          <AwUserpic :src="item.user.avatar" :name="item.user.name" />

          <div class="flex-1">
            <div>
              <strong>{{ item.user.name }}</strong>
              {{ item.action }}
            </div>
            <AwDescription>{{ item.timestamp }}</AwDescription>

            <div v-if="item.content" class="mt-2">
              {{ item.content }}
            </div>
          </div>
        </AwFlow>
      </template>
    </AwTimelineBuilder>
  </AwCard>
</template>
```

## Navigation

### Responsive Sidebar

Set up navigation menu in `plugins/menu.js`:

```javascript
// plugins/menu.js
export default function({ store }) {
  store.commit('awesIo/SET_MENU_ITEMS', {
    main: [
      {
        text: 'Dashboard',
        href: '/dashboard',
        icon: 'dashboard'
      },
      {
        text: 'Users',
        icon: 'users',
        key: 'users',
        href: '/users',
        children: [
          { text: 'All Users', href: '/users' },
          { text: 'Add User', href: '/users/create' },
          { text: 'Roles', href: '/roles' }
        ]
      },
      {
        text: 'Products',
        href: '/products',
        icon: 'box',
        badge: 5
      },
      {
        text: 'Settings',
        href: '/settings',
        icon: 'settings'
      }
    ]
  })
}
```

Layout component:

```markup
<!-- layouts/default.vue -->
<template>
  <AwLayout>
    <AwPage :title="currentPageTitle">
      <nuxt />
    </AwPage>
  </AwLayout>
</template>

<script>
export default {
  computed: {
    currentPageTitle() {
      return this.$route.meta.title || 'Dashboard'
    }
  }
}
</script>
```

## Modals & Dialogs

### Confirmation Dialog

```markup
<template>
  <AwModal :show="showConfirm" @close="showConfirm = false">
    <template #title>Confirm Delete</template>

    <AwDescription>
      Are you sure you want to delete this item? This action cannot be undone.
    </AwDescription>

    <template #buttons>
      <AwButton @click="confirmDelete" color="error">
        Delete
      </AwButton>
      <AwButton @click="showConfirm = false" color="mono">
        Cancel
      </AwButton>
    </template>
  </AwModal>
</template>

<script>
export default {
  data() {
    return {
      showConfirm: false,
      itemToDelete: null
    }
  },

  methods: {
    promptDelete(item) {
      this.itemToDelete = item
      this.showConfirm = true
    },

    async confirmDelete() {
      await this.$axios.delete(`/api/items/${this.itemToDelete.id}`)
      this.showConfirm = false
      this.$notify({ title: 'Item deleted successfully' })
    }
  }
}
</script>
```

### Form in Modal

```markup
<template>
  <AwPageModal
    title="Add Comment"
    theme="aside"
    @close="$router.back()"
  >
    <AwForm url="/api/comments" method="post" @sended="onCommentAdded">
      <AwTextarea
        name="content"
        label="Comment"
        rows="6"
        required
        autofocus
      />

      <AwUploader
        name="attachments"
        label="Attachments"
        multiple
      />
    </AwForm>

    <template #buttons>
      <AwButton type="submit">Post Comment</AwButton>
      <AwButton @click="$router.back()" color="mono">Cancel</AwButton>
    </template>
  </AwPageModal>
</template>
```

---

## More Examples

For more comprehensive patterns and recipes, see:

- **[Common Patterns](./common-patterns.md)** - Standard application patterns (list & detail, CRUD, search & filter, bulk actions)
- **[Advanced Patterns](./advanced-patterns.md)** - Complex patterns (multi-step wizards, nested forms, optimistic updates, real-time data)

## Related Documentation

- [Forms Guide](../guides/forms-guide.md) - Form patterns and validation
- [Page Patterns](../guides/page-patterns/) - List pages, detail pages, dashboards
- [Component Documentation](../index.md) - Complete component reference
