Choorai
Lv.2 Vue 3

Vue 3 Frontend

Build the same features as React using HTML-like template syntax. Experience the same API, different frontend philosophy firsthand.

Why Vue?

  • HTML-like template syntax makes it beginner-friendly
  • Two-way binding is simple with v-model
  • Uses the same TanStack Query as React
  • Composition API follows patterns similar to React Hooks

React vs Vue 3 Comparison

React Vue 3
useState ref() / reactive()
useEffect onMounted() / watch()
@tanstack/react-query @tanstack/vue-query
react-router-dom vue-router
JSX SFC Template (.vue)
children props <slot />

Project Structure

Folder Structure
examples/b2b-admin/web-vue/
├── src/
│   ├── main.ts              # App entry point
│   ├── App.vue              # Root component
│   ├── api/
│   │   └── client.ts        # API client (same as React)
│   ├── types/
│   │   └── api.ts           # Type definitions (same as React)
│   ├── composables/         # Vue Hooks (React's hooks/)
│   │   ├── useHealth.ts
│   │   └── useProjects.ts
│   ├── router/
│   │   └── index.ts         # Vue Router setup
│   ├── components/
│   │   ├── HealthStatus.vue
│   │   ├── AppLayout.vue
│   │   ├── ProjectForm.vue
│   │   └── ProjectCard.vue
│   └── pages/
│       ├── ProjectsPage.vue
│       └── ProjectDetailPage.vue
├── package.json
├── vite.config.ts
└── tailwind.config.js

Composition API Examples

State Management (ref)

React

React
const [name, setName] = useState('');

<input
  value={name}
  onChange={(e) => setName(e.target.value)}
/>

Vue 3

Vue
const name = ref('');

<input v-model="name" />

Vue Query Composable

composables/useProjects.ts
// composables/useProjects.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/vue-query';
import { computed, type Ref } from 'vue';
import { apiClient } from '../api/client';

export function useProjects(page: Ref<number> = ref(1)) {
  return useQuery({
    queryKey: computed(() => ['projects', page.value]),
    queryFn: () =>
      apiClient.get(`/api/v1/projects?page=${page.value}`),
  });
}

export function useCreateProject() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data) =>
      apiClient.post('/api/v1/projects', data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] });
    },
  });
}

Vue Component Example

components/ProjectForm.vue
<script setup lang="ts">
import { ref } from 'vue';
import { useCreateProject } from '../composables/useProjects';

const name = ref('');
const description = ref('');
const { mutate: createProject, isPending } = useCreateProject();

const handleSubmit = () => {
  if (!name.value.trim()) return;

  createProject(
    { name: name.value.trim(), description: description.value.trim() },
    {
      onSuccess: () => {
        name.value = '';
        description.value = '';
      },
    }
  );
};
</script>

<template>
  <form @submit.prevent="handleSubmit" class="space-y-4">
    <div>
      <label class="block text-sm font-medium text-gray-700 mb-1">
        Project Name
      </label>
      <input
        v-model="name"
        type="text"
        class="w-full px-3 py-2 border border-gray-300 rounded-lg"
        placeholder="Enter project name"
        required
      />
    </div>
    <button
      type="submit"
      :disabled="isPending"
      class="w-full bg-blue-600 text-white py-2 rounded-lg"
    >
      {{ isPending ? 'Creating...' : 'Create Project' }}
    </button>
  </form>
</template>

Running Locally

Terminal
# 1. Start the backend (Hono recommended)
cd examples/b2b-admin/api-hono
npm install
npm run dev

# 2. Start the Vue frontend (new terminal)
cd examples/b2b-admin/web-vue
npm install
npm run dev

# Open http://localhost:5174 in your browser

Cloudflare Pages Deployment

You can deploy to Cloudflare Pages just like React. The public/_redirects file is already included, which resolves SPA routing issues.

Framework preset Vite
Build command npm run build
Build output directory dist
Root directory examples/b2b-admin/web-vue

Key Points

  • The API client and type definitions are 100% identical to React
  • TanStack Query supports both React and Vue
  • The same backend API works regardless of the frontend framework

Last updated: February 22, 2026 · Version: v0.0.1

Send Feedback

Opens a new issue page with your message.

Open GitHub Issue