Build landing page using Island Architecture

mostafakmilly

Mostafa Milly

Posted on March 10, 2023

Build landing page using Island Architecture

Island architecture is a software architecture pattern that involves creating small, isolated, and self-contained modules, or "islands," that can communicate with each other through well-defined interfaces. Each island is designed to perform a specific function or set of related functions, and can be developed and maintained independently of the other islands. This makes it easier to build complex systems that are flexible, scalable, and maintainable over time.

What is Astro

Astro is a static site generator that is designed to help developers build modern, performant websites using a component-based architecture. It uses a combination of HTML, CSS, and JavaScript to generate static pages that can be hosted on a server or served from a content delivery network (CDN).

To use Astro with the island architecture pattern, you can break your website or web application into a set of islands, with each island representing a distinct feature or set of features. You can then use Astro to generate static pages for each island, along with the necessary JavaScript and CSS files, and deploy them to a CDN or server.

Island

Getting started

In this tutorial, you will learn how to create simple Astro page which contains multiple islands.

The target of this tutorial to build a simple landing page using Reactjs,Solidjs,Svelete and Vuejs.

Step 1: Set up the project

First, create a new Astro project using the following command:

npm create astro@latest
Enter fullscreen mode Exit fullscreen mode

For React Integration you can use the following command:

npx Astro add react
Enter fullscreen mode Exit fullscreen mode

For Solidjs integration you can use the following command:

npx Astro add solid
Enter fullscreen mode Exit fullscreen mode

For Vuejs integration you can use the following command:

npx Astro add vue
Enter fullscreen mode Exit fullscreen mode

Last for Svelete integration you can use the following command:

npx Astro add svelte
Enter fullscreen mode Exit fullscreen mode

Step 2: building layout component in Svelte

  • First create file under src/layouts and name it as Layout.svelte

layouts/Layout.svelte

<div class="container">
  <slot />
</div>

<style>
  .container {
    margin: 0 auto;
    padding: 0;
    display: flex;
    flex-direction: column;
    row-gap: 10px;
    width: 100%;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

In this component we create wrapper component for all our components.

By using <slot /> I can inject the children's components into the Layout Svelete component (It's kind of children prop inside Reactjs)

After creating the layout component, we can import it into our index.astro page under pages folder:

pages/index.astro

---
import Layout from "../layouts/Layout.svelte";
---

<Layout client:load>
</Layout>
Enter fullscreen mode Exit fullscreen mode
  • client:load directive enables to load and hydrate our layout component immediately as soon as possible.

You can learn more about client directives in this link

Step 3: Create a header component using Vuejs

  • First create file under src/components and name it as Header.vue

components/Header.vue

<template>
  <header>
    <h1>{{ title }}</h1>
    <nav>
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
    </nav>
  </header>
</template>

<script>
  export default {
    name: "Header",
    props: {
      title: {
        type: String,
        required: true,
      },
    },
  };
</script>

<style>
  header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    background-color: #fff;
    color: #262525;
  }

  h1 {
    margin: 0;
    font-size: 2rem;
  }

  nav ul {
    list-style: none;
    display: flex;
  }

  nav li {
    margin-right: 1rem;
  }

  nav a {
    color: #262525;
    text-decoration: none;
    font-weight: bold;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

After that we can import our Header Vuejs component into our Astro page:

pages/index.astro

---
import Layout from "../layouts/Layout.svelte";
import Header from "../components/Header.vue";
---

<Layout client:load>
  <Header title="Astro Islands" client:visible />
</Layout>
Enter fullscreen mode Exit fullscreen mode

As you can see, I can pass props to vue Header component.

client:visible is also client directive to load the component only if its visible on the user viewport

Step 4: Create hero section using Solidjs

  • First create file under src/components and name it as Hero.tsx

components/Hero.tsx

import { createSignal } from "solid-js";

function Hero() {
  const [isLoggedIn, setIsLoggedIn] = createSignal(false);

  function handleLogin() {
    setIsLoggedIn(true);
  }

  return (
    <div class="hero" style="padding: 3rem;">
      <div
        class="hero-content"
        style="background-color: #fff; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); margin-top: -4rem; z-index: 1;"
      >
        <div style="display : flex; column-gap:20px; margin-top : 8px">
          <img
            src="./hero.svg"
            alt="Hero image"
            style="max-width: 200px; height: auto; border-radius: 8px;"
          />
          <div>
            <h1 style="font-size: 3rem; margin-bottom: 1rem;">
              Welcome to our website
            </h1>
            <p style="font-size: 1.5rem; margin-bottom: 2rem;">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            </p>
            {!isLoggedIn() && (
              <button
                onClick={handleLogin}
                style="background-color: #007bff; color: #fff; padding: 1rem 2rem; border: none; border-radius: 4px; font-size: 1.2rem; cursor: pointer;"
              >
                Login
              </button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

export default Hero;
Enter fullscreen mode Exit fullscreen mode

After that we can import our Hero Solidjs component into our Astro page:

pages/index.astro

---
import Layout from "../layouts/Layout.svelte";
import Header from "../components/Header.vue";
import Hero from "../components/Hero.tsx";
---

<Layout client:load>
  <Header title="Astro Islands" client: visible />
  <Hero client:visible />
</Layout>
Enter fullscreen mode Exit fullscreen mode

Step 5: Create contact us form using Reactjs

  • First create file under src/components and name it as ContactForm.tsx

components/ContactForm.tsx

import React, { useState } from "react";
import "./ContactForm.css";

type ContactFormProps = {
  onSubmit?: (name: string, email: string, message: string) => void;
};

const ContactForm: React.FC<ContactFormProps> = ({ onSubmit }) => {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [message, setMessage] = useState("");

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    onSubmit?.(name, email, message);
  };

  return (
    <form className="contact-form" onSubmit={handleSubmit}>
      <div className="contact-form__field">
        <label className="contact-form__label">Name:</label>
        <input
          type="text"
          id="name"
          value={name}
          onChange={(e) => setName(e.currentTarget.value)}
          required
          className="contact-form__input"
        />
      </div>
      <div className="contact-form__field">
        <label className="contact-form__label">Email:</label>
        <input
          type="email"
          id="email"
          value={email}
          onChange={(e) => setEmail(e.currentTarget.value)}
          required
          className="contact-form__input"
        />
      </div>
      <div className="contact-form__field">
        <label className="contact-form__label">Message:</label>
        <textarea
          id="message"
          value={message}
          onChange={(e) => setMessage(e.currentTarget.value)}
          required
          className="contact-form__textarea"
        ></textarea>
      </div>
      <button type="submit" className="contact-form__submit">
        Submit
      </button>
    </form>
  );
};

export default ContactForm;
Enter fullscreen mode Exit fullscreen mode

After that we can import our ContactForm Reactjs component into our Astro page:

---
import Layout from "../layouts/Layout.svelte";
import Header from "../components/Header.vue";
import Hero from "../components/Hero.tsx";
import ContactForm from "../components/ContactForm.tsx";
---

<Layout client:load>
  <Header title="Astro Islands" client:visible />
  <Hero client:visible />
  <ContactForm client:visible />
</Layout>
Enter fullscreen mode Exit fullscreen mode

Step 6: Create footer component using Svelte

Last thing we want to create a footer component using Svelte so we will create our footer component file:

components/Footer.svelte

<footer class="footer">
  <nav class="footer__nav">
    <a href="#" class="footer__link">Home</a>
    <a href="#" class="footer__link">About</a>
    <a href="#" class="footer__link">Contact</a>
  </nav>
  <p class="footer__text">&copy; 2023 Astro Islands. All rights reserved.</p>
</footer>

<style>
  .footer {
    background-color: #f8f8f8;
    padding: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .footer__nav {
    display: flex;
    gap: 20px;
    margin-bottom: 10px;
  }

  .footer__link {
    color: #333;
    text-decoration: none;
    font-weight: bold;
    font-size: 1.2rem;
    transition: color 0.2s ease-in-out;
  }

  .footer__link: hover {
    color: #007bff;
  }

  .footer__text {
    font-size: 0.9rem;
    color: #333;
    margin-top: 10px;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Last thing we should modify our Astro page to include our Svelte Footer:

---
import Layout from "../layouts/Layout.svelte";
import Header from "../components/Header.vue";
import Hero from "../components/Hero.tsx";
import ContactForm from "../components/ContactForm.tsx";
import Footer from "../components/Footer.svelte";
---

<Layout client: load>
  <Header title="Astro Islands" client:visible />
  <Hero client:visible />
  <ContactForm client:visible />
  <Footer client:visible />
</Layout>
Enter fullscreen mode Exit fullscreen mode

In this way you create simple landing page using Reactjs, Vuejs , Solidjs and Svelte.

This is repository link: Link

Thank you for reading, and see you soon with another post ❤️

💖 💪 🙅 🚩
mostafakmilly
Mostafa Milly

Posted on March 10, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related