Skip to content

Vue Jobs: a Vue.js job board single-page application with full CRUD

A case study in structuring a small Vue.js SPA: routes for browsing, reading, adding and editing jobs, a REST API reached through Axios, and a responsive Tailwind CSS layout with validated forms.

Vue Jobs home page with a green Become a Vue Dev hero, For Developers and For Employers panels, and three job cards showing type, title, salary range and location

Vue Jobs is a Vue.js job board I built as a single-page application where employers can post Vue developer roles and job seekers can browse them. Every listing supports full CRUD: it can be created, read, updated and deleted through a RESTful API. Vue Router handles navigation, Axios handles the requests, and Tailwind CSS keeps the layout readable on a phone.

The problem

A job board is a small product with a complete loop inside it. An employer posts a role, a developer finds it in a list and opens the full description, and later the employer corrects the salary or takes the listing down. Each step is a different view with different data needs, and all of them must agree about the same record.

Built as separate server-rendered pages, every step is a full reload, and after an edit the user can land on a list that does not yet show the change. I wanted the loop inside one page that stays loaded, while the address bar still meant something: a link to a job should open that job, and the back button should do what people expect.

My role

I built the front end: the component structure, the routes, the validated forms, the Axios layer that talks to the REST API, and the Tailwind CSS styling, which lays the job cards out in one column on a phone and three across on a wide screen. I kept the stack small and put the effort into component boundaries and data flow.

Architecture and tech stack

Vue Router for an SPA that keeps real URLs

Each part of the loop has its own route: home, the full job list, a single job, and the add and edit forms. Job routes take the listing id as a parameter, so a job can be bookmarked or shared and loads its own data when opened directly. Moving between views swaps components without a page reload, which is most of why the board feels quick on a phone.

Axios requests kept in one layer

Calls to the REST API go through a small set of functions instead of being written inline in components. A component asks for the jobs, or asks to save a job, and never needs to know the URL or the HTTP method behind it. If the API address or a response shape changes, there is one file to update.

Component state instead of a global store

The data here is page-shaped: the list page owns the list, the job page owns one job, and each form owns its fields. Keeping that state in the components that use it, with a job passed down to its card as props, was simpler than a store for data no other view shares. After a create, update or delete, the app navigates to a page that fetches fresh data, so no cached copy can go stale.

That is the opposite call to the one I made for the Redux Toolkit Kanban board in my MERN team management system, where one task shows up in several views at once and a shared store earns its place.

Key features

  • Full CRUD for job postings: create a listing, read it in the list or on its own page, update any field, or delete it.
  • Client-side routing: Home, Jobs, Add Job and a page for each listing, all without a page reload.
  • Job cards that summarise a listing: type, title, a truncated description with a More toggle, salary range and location, plus a Read More link to the full page.
  • Validated forms for adding and editing a job, so a listing cannot be saved without the details a job seeker needs.
  • Separate entry points for each audience: a For Developers panel that leads to the listings and a For Employers panel that leads to the Add Job form.

Challenges and how I solved them

One form for adding and editing

Problem
Adding and editing a job need nearly the same form, but one starts empty and posts a new record, while the other loads an existing job and sends an update. Two copies of the form would drift apart the first time a field was added to only one.
Solution
The edit view fetches the job by the id in the route and fills the same fields the add view uses, and the submit handler sends a create or an update depending on whether an id is present. Validation rules are written once and apply to both.

Showing progress and failure honestly

Problem
Every view depends on a network request, and on a slow connection a blank page looks like a broken one. A delete that fails silently is worse: the user thinks the listing is gone while it is still live.
Solution
Each view shows a loading state until its data arrives, and actions that change data only navigate away once the API confirms them. A failed request leaves the user on the same screen with their input intact.

Deep links into a single-page app

Problem
An SPA behaves well until someone refreshes on a job page or opens a shared link. The server is then asked for a path it has no file for, and answers with a 404.
Solution
The host serves the app for every route and lets Vue Router resolve the path, and each job page loads its listing by id when it mounts rather than relying on data handed over from the list.

Results

Vue Jobs runs the whole posting loop inside one page. The home screen, shown in the screenshot, sends developers to the listings and employers to the Add Job form, the Jobs page shows every role as a card, and each card opens a full listing that can be edited or deleted.

Keeping requests in their own layer carries across frameworks. It appears again in SafeGuard Tracking, a React GPS dashboard with centralized API handling, where Context API and custom hooks do the job that Vue components and Axios helpers do on this Vue.js job board.

What's next

With more time I would add search and filters by job type and location, and move listings into a store such as Pinia once more than one view needs them, for example a saved-jobs list for developers.

Need a full-stack developer for a product like this?

I work remotely with teams in the US, Canada, the UK, Europe and the Gulf, and with clients across Pakistan. Based in Pakistan (PKT, UTC+5), available for freelance and full-time roles.