How to Nuxt

Getting started with a landing page

1/23/2024

Jane

A person operates a technical device. On each corner of the rectangular image are the logos of nuxt, daisyUI, tailwind CSS and GEPROG.

Finding the perfect blend of creativity and efficiency can be a real challenge in the world of web design. There seem to be as many front-end frameworks as there are sand on the beach, which makes it difficult to choose the right one for our company's website. In the past, we have developed our website using Gatsby.js, a static site generator based on React. However, the poor developer experience with Gatsby.js and our preference for Vue.js led us to explore other options. We discovered the Vue.js based open source framework Nuxt 3 and promptly decided to re-write our website.

The new GEPROG site's tech stack

The tech stack for the GEPROG website consists of Nuxt 3, various Nuxt plugins, daisyUI based on Tailwind CSS, and Tailwind CSS itself.

Tailwind CSS is a utility-first CSS framework allowing developers to use predefined classes for colour, spacing and layout. Instead of writing custom classes and meticulously structuring everything, developers can use these predefined classes, making the development process faster and more flexible.

DaisyUI, based on Tailwind CSS, is a component library that makes it easy to quickly integrate UI elements such as cards, lists, menus or navigation. We chose this library because websites should be built modularly, and daisyUI allows you to quickly create components without writing extensive class definitions using Tailwind CSS. However, there were challenges associated with the component library. Occasionally we had to create our own UI elements because it would have been too cumbersome to modify the daisyUI class. Nevertheless, the library is excellent for a quick start.

Getting Started

To initiate a Nuxt 3 project, ensure your terminal has pnpm, which you can install using the Node Package Manager (npm):

# bash
npm install -g pnpm

Subsequently, create your Nuxt 3 project:

# bash
pnpm dlx nuxi@latest init <project-name>

For more information, consult the Nuxt 3 documentation. Utilize pnpm to generate the Nuxt project and continue with pnpm for the project:

# bash
cd <project-name>
code .
pnpm install

But which dependencies should you install?

Dependencies

A variety of dependencies significantly eased development. First and foremost, as mentioned earlier, add Tailwind CSS:

# bash
pnpm i -D @nuxtjs/tailwindcss

Subsequently, initialize the tailwind.config.js:

# bash
pnpx tailwindcss init

To apply Tailwind CSS, add it to nuxt.config.ts:

// ./nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
  devtools: { enabled: true },
});

To use the daisyUI plugin and set themes in tailwind.config.js, install daisyUI:

# bash
pnpm install -D daisyui@latest

In tailwind.config.js, set the plugin daisyUI:

// ./tailwind.config.js
plugins: [require('daisyui')],

Now, set your daisyUI theme:

// ./tailwind.config.js
daisyui: {
    themes: [
        {
            companytheme: {
                primary: '#5C8374',
                secondary: '#9EC8B9',
                accent: '#1B4242',
                neutral: '#092635',
            },
        },
    ],
},

The colour combination is provided by ColorHunt. Alternatively, choose a predefined theme here. How do you inform Nuxt 3 that this is the theme you want to use? Utilize Layouts to achieve this, allowing the definition of elements like Navbar and Footer for consistent display on every page not defining its layout. This layout, named default.vue, resides in a new layouts folder: ./layouts/default.vue. In default.vue, include:

<!-- ./layouts/default.vue -->
<template>
  <div data-theme="companytheme"></div>
</template>

Time to run your website locally - ./package.json tells you which script will run the dev environment. It could be dev or start so look that up first. In case of dev you can write the following:

# bash
pnpm dev

In case of start - just switch dev for start. But why is the page already filled with content by Nuxt? Nuxt provides an index page. You can delete the page by adjusting or removing app.vue. To make the right decision, consider whether you want a single page or a page with multiple subpages. As Nuxt handles routing, it's better to create the pages folder for multiple subpages. Delete app.vue and add the pages folder under your project's root: ./pages Inside pages, add an index.vue and more pages like contact.vue or about.vue. However, for a single page, delete <NuxtWelcome /> inside app.vue and add your content and styling.

Start the Design

If aiming for a simple landing page for a product, such as selling a solar system (😉), download pictures from Unsplash, thanks to Simon Lee for the pictures. You can see his collection here. For a single page, delete <NuxtWelcome /> in the app.vue. Now, plan the layout of the landing page. Looking up different landing pages, their components can be boiled down to these points:

  1. Header
  2. Hero section
  3. Feature section
  4. Pricing section
  5. Testimonial section
  6. FAQ section
  7. Contact section/Footer

For each section, create a component in the components folder: ./components

You need a header that consistently showcases the name of your product or company alongside an engaging call-to-action button. Fortunately, you can leverage daisyUI's Navbar component to achieve this effortlessly. Resulting in the creation of the Header.vue component:

<!-- ./components/Header.vue -->
<template>
  <header class="navbar fixed z-10 glass shadow-sm">
    <div class="navbar-start">
      <a class="btn btn-ghost text-xl">LandingPage</a>
    </div>
    <div class="navbar-end">
      <a class="btn btn-secondary">Call to Action</a>
    </div>
  </header>
</template>

Now, seamlessly integrate this into your default.vue layout:

<!-- ./layouts/default.vue -->
<template>
  <div data-theme="companytheme" class="bg-neutral text-white">
    <Header />
    <main class="p-8 flex flex-col gap-4 max-w-screen-lg mx-auto">
      <slot />
    </main>
  </div>
</template>

As Nuxt does not handle routing by default, manually add <NuxtLayout> to your app.vue:

<!-- ./app.vue -->
<template>
  <NuxtLayout> </NuxtLayout>
</template>

Hero Section

Elevate your landing page with a captivating Hero Section. To efficiently manage images and compress them, install NuxtPictures:

# bash
pnpm add @nuxt/image

Add it to nuxt.config.ts:

// ./nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    dir: 'assets/images',
  },
});

You can find a guide to NuxtPictures on this blog here. Now, seamlessly add the Hero section using the Hero.vue component:

<!-- ./components/Hero.vue -->
<template>
  <div class="hero h-screen">
    <div class="hero-content flex-col lg:flex-row-reverse">
      <div class="max-w-sm">
        <NuxtPicture
          src="simon-lee-_B7LjqNXu5Q-unsplash.jpg"
          :img-attrs="{
            alt: 'hero',
            class: 'w-full rounded-lg shadow-2xl',
          }"
        />
      </div>
      <div>
        <h1 class="text-5xl font-bold">Get your own Solar System</h1>
        <p class="py-6">
          Own a piece of the cosmos! Experience the beauty of the solar system like never before. Your cosmic journey
          starts here. Seize the opportunity today!
        </p>
        <button class="btn btn-secondary">Call to action</button>
      </div>
    </div>
  </div>
</template>

Feature Section

Effectively communicate your product's capabilities through the Feature.vue component.

<!-- ./components/Feature.vue -->
<template>
  <div
    class="flex flex-col items-center gap-4 px-4 xl:px-0 lg:flex-row lg:justify-between"
    :class="reverse ? 'lg:flex-row-reverse' : ''"
  >
    <div class="lg:w-1/2 text-center lg:text-left">
      <h2 class="font-bold text-2xl">{{ title }}</h2>
      <p class="text-lg">
        {{ text }}
      </p>
    </div>
    <NuxtPicture
      v-if="imagePath"
      format="avif, webp"
      class="flex"
      :class="reverse ? 'justify-start' : 'justify-end'"
      :src="imagePath"
      :img-attrs="{ alt: imgAlt, class: 'w-full sm:w-2/3 rounded-lg' }"
    />
  </div>
</template>

<script setup lang="ts">
defineProps<{
  title: string;
  text: string;
  imagePath: string;
  imgAlt: string;
  reverse?: boolean;
}>();
</script>

Utilize an array of objects in app.vue to render multiple features. Use v-for to render multiple features at once.:

<!-- ./app.vue -->
<template>
  <!-- ... (previous content) ... -->
  <Feature
    v-for="feature in features"
    :key="feature.id"
    :title="feature.title"
    :text="feature.text"
    :imagePath="feature.imagePath"
    :imgAlt="feature.imgAlt"
    :reverse="feature.id % 2 === 0"
  />
</template>

Pricing Section

To transparently tell your users what your offer costs you can add pricing cards. One idea could be this:

<!-- ./components/Pricing.vue -->
<template>
  <div class="flex flex-col justify-between items-center bg-primary rounded-md w-full md:w-1/3 p-4 gap-4">
    <h3 class="text-xl">{{ title }}</h3>
    <p class="font-bold text-2xl">{{ cost }}€</p>
    <p class="text-center">{{ text }}</p>
    <button class="btn btn-secondary"><a href="">Call to action</a></button>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  title: string;
  cost: string;
  text: string;
}>();
</script>

Testimonial Section

Boost your service credibility by incorporating testimonials using the Testimonial.vue component:

<!-- ./components/Testimonial.vue -->
<template>
  <div class="flex w-full md:w-1/3 rounded-md shadow-md p-4 bg-accent">
    <div class="flex gap-2 md:flex-col md:items-center">
      <NuxtPicture
        :src="imagePath"
        class="w-full sm:w-1/2 flex justify-center items-center"
        :img-attrs="{
          alt: imgAlt,
          class: 'rounded-full',
        }"
      />
      <div>
        <h3 class="card-title">{{ author }}</h3>
        <p>{{ text }}</p>
      </div>
    </div>
  </div>
</template>

FAQ Section

Address customer concerns with an FAQ section. Leverage the Collapsible component for each question-answer pair:

<!-- ./components/Faq.vue -->
<template>
  <details class="collapse collapse-arrow">
    <summary class="collapse-title text-xl font-medium">{{ title }}</summary>
    <div class="collapse-content">
      <p>{{ text }}</p>
    </div>
  </details>
</template>

Conclude your landing page with a polished footer. Utilize daisyUI's Footer component and customize it according to your preferences:

<!-- ./components/Footer.vue -->
<template>
  <footer class="footer p-10 bg-neutral">
    <aside>
      <p class="font-bold">LandingPage</p>
      <p class="text-base">
        Made by
        <a href="<https://geprog.com/>" target="_blank" rel="noreferrer" class="underline">GEPROG</a>
      </p>
    </aside>
    <p>
      Pictures are Downloaded on Unsplash and provided by
      <a href="<https://unsplash.com/de/@simonppt>" class="underline">Simon Lee</a>
    </p>
  </footer>
</template>

Side note : it is important to have on each component and page <template></template>. Otherwise, your code will not compile as this leads to an error message.

Side note 2 : The text for the landing page is generated by ChatGPT. However, the code and this blog post is created by us.

Conclusion

And there we have it. A fully functional landing page that you can adjust to your liking. You can find the repository for this project on GitHub or have a look at the page here. Visit daisyUI to find more handy components to use and experiment with colours and compositions. We hope this was helpful, and happy coding.

Nuxt 3
Framework
Frontend Development
Zurück zum Blog