ReactJS is a powerful JavaScript library that allows you to create dynamic and interactive user interfaces. With its component-based structure, we'll demonstrate how to build a modern and visually appealing real estate website that adapts to different screen sizes and devices.
📌 What I have used to create this project:
- HTML
- CSS
- React JS
Source Code
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet" />
<title>Real Estate</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
index.css
:root {
--primary: #1f3e72;
--secondary: rgba(255, 255, 255, 0.78);
--black: #131110;
--blue-gradient: linear-gradient(97.05deg, #4066ff 3.76%, #2949c6 100%);
--orange-gradient: linear-gradient(270deg, #ffb978 0%, #ff922d 100%);
--blue: #4066ff;
--lightBlue: #eeeeff;
--shadow: 0px 23px 21px -8px rgba(136, 160, 255, 0.25);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
scroll-behavior: smooth;
}
a {
color: inherit;
text-decoration: none;
}
.paddings {
padding: 1.5rem;
}
.innerWidth {
width: 100%;
}
.flexCenter {
display: flex;
row-gap: 2rem;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.flexStart {
display: flex;
justify-content: flex-start;
align-items: center;
}
.flexEnd {
display: flex;
justify-content: flex-end;
align-items: center;
}
.flexColCenter {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.flexColStart {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
}
.flexColEnd {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-end;
}
.primaryText {
color: #1f3e72;
font-weight: bold;
font-size: 2rem;
}
.secondaryText {
color: rgb(140 139 139);
font-size: 0.9rem;
}
.orangeText {
color: orange;
font-size: 1.5rem;
font-weight: 600;
}
.button {
font-weight: 500;
padding: 0.6rem 1.4rem;
color: white;
background: var(--blue-gradient);
border: none;
border-radius: 4px;
transition: all 300ms ease-in;
}
.button:hover {
cursor: pointer;
transform: scale(1.1);
}
/* media queries */
@media (min-width: 1536px) {
.innerWidth {
max-width: 1280px;
margin: auto;
}
}
@media (min-width: 640px) {
.paddings {
padding: 4rem;
}
}
@media (min-width: 1280px),
(min-width: 768px) {
.paddings {
padding: 2rem;
}
}
@media (max-width: 640px) {
.primaryText {
font-size: 1.5rem;
}
.orangeText {
font-size: 1.2rem;
}
}
main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.css
.App {
position: relative;
overflow-x: clip;
}
.App>:nth-child(1) {
background: var(--black);
position: relative;
}
.white-gradient {
z-index: 99;
position: absolute;
width: 20rem;
height: 20rem;
background: rgba(255, 255, 255, 0.522);
filter: blur(100px);
border-radius: 100px;
}
accordion.jsx
import { HiShieldCheck } from "react-icons/hi";
import { MdCancel, MdAnalytics } from "react-icons/md";
const data = [
{
icon: <HiShieldCheck/>,
heading: "Best interest rates on the market",
detail:
"Exercitation in fugiat est ut ad ea cupidatat ut in cupidatat occaecat ut occaecat consequat est minim minim esse tempor laborum consequat esse adipisicing eu reprehenderit enim.",
},
{
icon: <MdCancel />,
heading: "Prevent unstable prices",
detail:
"Exercitation in fugiat est ut ad ea cupidatat ut in cupidatat occaecat ut occaecat consequat est minim minim esse tempor laborum consequat esse adipisicing eu reprehenderit enim.",
},
{
icon: <MdAnalytics />,
heading: "Best price on the market",
detail:
"Exercitation in fugiat est ut ad ea cupidatat ut in cupidatat occaecat ut occaecat consequat est minim minim esse tempor laborum consequat esse adipisicing eu reprehenderit enim.",
},
];
export default data;
common.js
export const sliderSettings = {
slidesPerView: 1,
spaceBetween: 50,
breakpoints: {
480: {
slidesPerView: 1,
},
600: {
slidesPerView: 2,
},
750: {
slidesPerView: 3,
},
1100: {
slidesPerView: 4,
},
},
};
slider.json
[
{
"name": "Aliva Priva Jardin",
"price": "47,043",
"detail": "Jakarta Garden City Street, Cakung. Pulo Gadung, Jakarta Timur, DKI Jakarta",
"image": "./r1.png"
},
{
"name": "Asatti Garden City",
"price": "66,353",
"detail": "Pahlawan Street XVII No.215, Cinangka, Sawangan, Depok, Jawa Barat",
"image": "./r2.png"
},
{
"name": "Citralan Puri Serang",
"price": "35,853",
"detail": "Ruko Puri Indah Residence Block A7, Lingkar Street, Ciracas, Serang, Banten",
"image": "./r3.png"
},
{
"name": "Aliva Priva Jardin",
"price": "47,043",
"detail": "Jakarta Garden City Street, Cakung. Pulo Gadung, Jakarta Timur, DKI Jakarta",
"image": "./r1.png"
},
{
"name": "Asatti Garden City",
"price": "66,353",
"detail": "Pahlawan Street XVII No.215, Cinangka, Sawangan, Depok, Jawa Barat",
"image": "./r2.png"
},
{
"name": "Citralan Puri Serang",
"price": "35,853",
"detail": "Ruko Puri Indah Residence Block A7, Lingkar Street, Ciracas, Serang, Banten",
"image": "./r3.png"
}
]
Companies.jsx
import React from 'react';
import './Companies.css';
const Companies = () => {
return (
<section className="c-wrapper">
<div className='c-container paddings innerWidth flexCenter'>
<img src="./prologis.png" alt="" />
<img src="./tower.png" alt="" />
<img src="./equinix.png" alt="" />
<img src="./realty.png" alt="" />
</div>
</section>
);
};
export default Companies;
Companies.css
import React from 'react';
import './Companies.css';
const Companies = () => {
return (
<section className="c-wrapper">
<div className='c-container paddings innerWidth flexCenter'>
<img src="./prologis.png" alt="" />
<img src="./tower.png" alt="" />
<img src="./equinix.png" alt="" />
<img src="./realty.png" alt="" />
</div>
</section>
);
};
export default Companies;
Contact.jsx
import React from 'react';
import { MdCall } from 'react-icons/md';
import {BsFillChatDotsFill} from 'react-icons/bs';
import {HiChatBubbleBottomCenter} from 'react-icons/hi2';
import './Contact.css';
const Contact = () => {
return (
<section className="c-wrapper">
<div className="c-container paddings innerWidth flexCenter">
{/* left side */}
<div className="c-left flexColStart">
<span className='orangeText'>Our Contact Us</span>
<span className='primaryText'>Easy to contact us</span>
<span className='secondryText'>We always ready to help by providijng the best services for you. We beleive a good blace to live can make your life better</span>
<div className="contactModes flexColStart">
{/* first row */}
<div className="row flexStart">
{/* first mode */}
<div className="mode flexColCenter">
<div className='flexStart'>
<div className="icon flexCenter">
<MdCall size={25}/>
</div>
<div className="detail flexColStart">
<span className='primaryText'>Call</span>
<span className='secondryText'>021 123 145 14</span>
</div>
</div>
<div className='button flexCenter' >Call Now</div>
</div>
{/* Second mode */}
<div className="mode flexColCenter">
<div className='flexStart'>
<div className="icon flexCenter">
<BsFillChatDotsFill size={25}/>
</div>
<div className="detail flexColStart">
<span className='primaryText'>Chat</span>
<span className='secondryText'>021 123 145 14</span>
</div>
</div>
<div className='button flexCenter' >Chat Now</div>
</div>
</div>
{/* second row */}
<div className="row flexStart">
{/* third mode */}
<div className="mode flexColCenter">
<div className='flexStart'>
<div className="icon flexCenter">
<BsFillChatDotsFill size={25}/>
</div>
<div className="detail flexColStart">
<span className='primaryText'> Video Call</span>
<span className='secondryText'>021 123 145 14</span>
</div>
</div>
<div className='button flexCenter' > Video Call Now</div>
</div>
{/* fourth mode */}
<div className="mode flexColCenter">
<div className='flexStart'>
<div className="icon flexCenter">
<HiChatBubbleBottomCenter size={25}/>
</div>
<div className="detail flexColStart">
<span className='primaryText'>Message</span>
<span className='secondryText'>021 123 145 14</span>
</div>
</div>
<div className='button flexCenter' >Message Now</div>
</div>
</div>
</div>
</div>
{/* right side */}
<div className="c-right flexEnd">
<div className="image-container">
<img src="./contact.jpg" alt="" />
</div>
</div>
</div>
</section>
);
};
export default Contact;
Contact.css
.c-container {
justify-content: space-between;
}
.c-container>div {
flex: 1;
}
.c-right {
width: 100%;
}
.c-left {
gap: 0.5 rem;
}
.contactModes {
margin-top: 2rem;
gap: 1rem;
}
.contactModes .row {
gap: 1.5rem;
}
.mode {
width: 16rem;
padding: 1rem;
border: 0.8px solid rgba(128, 128, 128, 0.143);
border-radius: 5px;
gap: 1rem;
transition: all 300ms ease-in;
}
.mode .button {
width: 100%;
background: var(--lightBlue);
color: var(--blue);
font-size: 0.9rem;
font-weight: 600;
}
.mode >:nth-child(1) {
width: 100%;
gap: 1.6rem;
}
.mode .detail .primaryText {
font-size: 1.1rem;
font-weight: 600;
}
.mode:hover {
scale: 1.1;
box-shadow: var(--shadow);
}
.mode .button:hover {
background: var(--blue-gradient);
color: white;
scale: 0.8;
}
@media(max-width: 1024px) {
.c-container {
flex-direction: column;
}
.c-right {
justify-content: center;
}
.contactModes {
width: 100%;
}
.row {
flex-direction: column;
width: 100%;
}
.mode {
width: 100%;
}
}
Footer.jsx
import React from 'react';
import './Footer.css'
const Footer = () => {
return (
<section className="f-wrapper">
<div className="f-container paddings innerWidth flexCenter">
{/* left side */}
<div className="f-left flexColStart">
<img src="./logo2.png" alt="" width={120} />
<span className='secondryText'>Our vision is to make all people <br />
the best place to live for them.</span>
</div>
{/* right side */}
<div className="f-right flexColStart">
<span className='primaryText'>Information</span>
<span className='secondryText'>145 New York, FL 5467, USA</span>
<div className="f-menu flexCenter">
<span>Property</span>
<span>Services</span>
<span>Product</span>
<span>About Us</span>
</div>
</div>
</div>
</section>
);
};
export default Footer;
Footer.css
.f-container {
justify-content: space-between;
}
.f-left {
gap: 1rem;
}
.f-menu {
gap: 1.5rem;
margin-top: 1.5rem;
font-weight: 500;
}
@media (max-width: 768px) {
.f-container {
justify-content: center;
}
.f-container>div {
align-items: center;
text-align: center;
}
}
GetStarted.jsx
import React from 'react';
import './GetStarted.css'
const GetStarted = () => {
return (
<section className="g-wrapper">
<div className="g-container paddings innerWidth">
<div className='flexColCenter inner-container'>
<span className='primaryText'>Get started with Homyz</span>
<span className='secondryText'>Subscribe and find super attractive price quotes from us. <br />
Find your residence soon</span>
<button className='button'>
<a href="mailto:basaksubroto@gmail.com">Get Started</a>
</button>
</div>
</div>
</section>
);
};
export default GetStarted;
GetStarted.css
.inner-container {
gap: 1.5rem;
background: #4161df;
padding: 2rem;
border-radius: 10px;
border: 6px solid #5d77d6;
text-align: center;
}
.inner-container .primaryText {
color: white;
font-weight: 600;
}
.inner-container .secondryText {
color: rgba(255, 255, 255, 0.87);
}
.inner-container .button {
background: #5a83d7;
border: 2px solid white;
box-shadow: var(--shadow);
border-radius: 10px;
}
Header.jsx
import React, { useState } from 'react';
import { BiMenuAltRight } from 'react-icons/bi'
import OutsideClickHandler from 'react-outside-click-handler';
import './Header.css'
const Header = () => {
const [menuOpend, setMenuOpend] = useState(false)
const getMenuStyles = (menuOpend) => {
if (document.documentElement.clientWidth <= 800) {
return { right: !menuOpend && "-100%" }
}
}
return (
<section className='h-wrapper'>
<div className='flexCenter paddings innerWidth h-container'>
<img src="./logo.png" alt="logo" width={100} />
<OutsideClickHandler onOutsideClick={() =>
setMenuOpend (false)}>
<div className='flexCenter h-menu' style={getMenuStyles(menuOpend)}>
<a href="">Residencies</a>
<a href="">Our Value</a>
<a href="">Contact Us</a>
<a href="">Get Started</a>
<button className='button'>Contact</button>
</div>
</OutsideClickHandler>
<div className="menu-icon" onClick={() => setMenuOpend((prev) => !prev)}>
<BiMenuAltRight size={30} />
</div>
</div>
</section>
);
};
export default Header;
Header.css
.h-wrapper {
background-color: var(--black);
color: white;
z-index: 99;
}
.h-container {
justify-content: space-between;
padding-top: 1rem;
padding-bottom: 1rem;
color: var(--secondary);
}
.h-menu {
gap: 2rem;
}
.menu-icon {
display: none;
}
.h-menu > *:hover {
cursor: pointer;
}
@media (max-width: 786px) {
.menu-icon {
display: block;
}
.h-menu {
z-index: 99;
color: var(--black);
position: absolute;
top: 3rem;
right: 3rem;
background: white;
flex-direction: column;
font-weight: 500;
gap: 2rem;
padding: 3rem;
border-radius: 10px;
align-items: flex-start;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.05);
transition: all 300ms ease-in;
}
}
Hero.jsx
import React from 'react';
import { HiLocationMarker } from "react-icons/hi";
import CountUp from 'react-countup';
import './Hero.css'
import { motion } from 'framer-motion';
const Hero = () => {
return (
<section className="hero-wrapper">
<div className="hero-container flexCenter paddings innerWidth">
{/* left side */}
<div className="hero-left flexColStart">
<div className="hero-title">
<div className="orange-circle" />
<motion.h1
initial={{ y: "2rem", opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{
duration: 2,
type: "spring"
}}>
Discover <br />
Most Suitable <br />
Property
</motion.h1>
</div>
<div className="hero-description flexColStart">
<span className='secondaryText'>Find a variety of properties that suit you very easilty</span>
<span className='secondaryText'>Forget all difficulties in finding a residence for you</span>
</div>
<div className="search-bar flexCenter">
<HiLocationMarker color="var(--blue) " size={25} />
<input type="text" />
<button className='button'>Search</button>
</div>
<div className="stats flexCenter">
<div className="stat flexColCenter ">
<span><CountUp start={8800} end={9000} duration={4} />
<span>+</span>
</span>
<span className='secondaryText'>Premium Products</span>
</div>
<div className="stat flexColCenter ">
<span><CountUp start={1950} end={2000} duration={4} />
<span>+</span>
</span>
<span className='secondaryText'>Happy Customers</span>
</div>
<div className="stat flexColCenter ">
<span><CountUp end={28} />
<span>+</span>
</span>
<span className='secondaryText'>Award Winings</span>
</div>
</div>
</div>
{/* right side */}
<div className="flexCenter hero-right">
<motion.div
initial={{ x: "7rem", opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{
duration: 2,
type: "spring"
}} className="image-container">
<img src="./hero-image.png" alt="hero image" />
</motion.div>
</div>
</div>
</section>
);
};
export default Hero;
Hero.css
.hero-wrapper {
color: white;
position: relative;
padding-bottom: 2rem;
background-color: var(--black);
z-index: 1;
}
.hero-container {
justify-content: space-around;
align-items: center;
}
/* left side */
.hero-left {
gap: 3rem;
}
.hero-title {
position: relative;
z-index: 1;
}
.hero-left h1 {
font-weight: 600;
font-size: 3.8rem;
line-height: 4rem;
}
.orange-circle {
height: 4rem;
width: 4rem;
background: var(--orange-gradient);
border-radius: 999px;
position: absolute;
z-index: -1;
right: 28%;
top: -10;
}
.search-bar {
background-color: white;
border-radius: 5px;
border: 3px solid rgba(120, 120, 120, 0.374);
padding: 0.5rem 1rem;
justify-content: space-between;
width: 100%;
}
.search-bar input {
border: none;
outline: none;
}
.stats {
width: 100%;
justify-content: space-between;
}
.stat > :nth-child(1) {
font-size: 2rem;
}
.stat > :nth-child(1) > :last-child {
color: orange;
}
/* right side */
.image-container {
width: 30rem;
height: 35rem;
overflow: hidden;
border-radius: 15rem 15rem 0 0;
border: 8px solid rgba(255, 255, 255, 0.12);
}
.image-container img {
height: 100%;
width: 100%;
}
@media (max-width: 640px) {
.hero-container {
margin-top: 2rem;
}
.hero-title {
font-size: 2.5rem;
line-height: 3rem;
}
.image-container {
width: 100%;
height: 100%;
}
.stats {
justify-content: center;
gap: 1.5rem;
}
.hero-right {
width: 100%;
}
.stat>:nth-child(1) {
font-size: 1.5rem;
}
.stat>:nth-child(2) {
font-size: 1.5rem;
}
}
Residencies.jsx
import React from 'react';
import { Swiper, SwiperSlide, useSwiper } from 'swiper/react';
import 'swiper/css';
import data from '../../utils/slider.json';
import { sliderSettings } from '../../utils/common';
import './Residencies.css';
const Residencies = () => {
return (
<section className="r-wrapper">
<div className="r-contianer paddings innerWidth">
<div className="r-head flexColStart">
<span className='orangeText'>Best Choices</span>
<span className='primaryText'>Popular Residencies</span>
</div>
<Swiper {...sliderSettings}>
<SliderButtons />
{
data.map((card, i) => (
<SwiperSlide key={i}>
<div className="r-card flexColStart">
<img src={card.image} alt="home" />
<span className='r-price secondaryText'>
<span style={{ color: "orange" }}>$</span>
<span>{card.price}</span>
</span>
<span className='primaryText'>{card.name}</span>
<span className='SecondryText'>{card.name}</span>
</div>
</SwiperSlide>))
}
</Swiper>
</div>
</section>
);
};
export default Residencies;
const SliderButtons = () => {
const swiper = useSwiper();
return (
<div className='r-buttons flexCenter'>
<button onClick={() => swiper.slidePrev()}><</button>
<button onClick={() => swiper.slideNext()}>></button>
</div>
);
}
Residencies.css
.r-contianer {
overflow: hidden;
position: relative;
}
.r-head {
margin-bottom: 2rem;
}
.r-card {
gap: 0.6rem;
padding: 1rem;
border-radius: 10px;
max-width: max-content;
margin: auto;
transition: all 300ms ease-in;
}
.r-card>img {
width: 100%;
max-width: 15rem;
}
.r-card>:nth-child(2)
{
font-size: 1.2rem;
font-weight: 600;
}
.r-card>:nth-child(3) {
font-size: 1.5rem;
}
.r-card>:nth-child(4) {
font-size: 0.7rem;
width: 15rem;
}
.r-card:hover {
scale: 1.025;
cursor: pointer;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0) 0%,
rgba(136, 160, 255, 0.46) 217.91%
);
box-shadow: 0px 72px 49px -51px rgba(136, 160, 255, 0.21);
}
.swiper-horizontal {
overflow: visible;
}
.r-buttons {
position: absolute;
gap: 1rem;
top: -4rem;
right: 0;
}
.r-buttons button {
font-size: 1.2rem;
padding: 0.2rem 0.8rem;
color: blue;
border: none;
border-radius: 5px;
background-color: white;
cursor: pointer;
}
.r-buttons > :nth-child(1) {
background-color: #eeeeff;
}
.r-buttons > :nth-child(2) {
box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.25);
}
@media (max-width: 640px) {
.r-head {
align-items: center;
}
.r-buttons {
position: initial;
}
}
Value.jsx
import React, { useState } from 'react';
import {
Accordion,
AccordionItem,
AccordionItemHeading,
AccordionItemButton,
AccordionItemPanel,
AccordionItemState
} from 'react-accessible-accordion';
import { MdOutlineArrowDropDown } from 'react-icons/md';
import "react-accessible-accordion/dist/fancy-example.css";
import data from '../../utils/accordion';
import './Value.css';
const Value = () => {
return (
<section className="v-wrapper">
<div className="v-container paddings innerWidth flexCenter">
{/* Left side */}
<div className="v-left">
<div className="image-container">
<img src="./value.png" alt="" />
</div>
</div>
{/* right side */}
<div className="v-right flexColStart">
<span className='orangeText'>Our Value</span>
<span className='primaryText'>Value We Give to You</span>
<span className='secondaryText'>We always ready to help by providijng the best services for you.
<br />
We beleive a good blace to live can make your life better</span>
<Accordion
className='accordion'
allowMultipleExpanded={false}
preExpanded={[0]}>
{data.map((item, i) => {
const [className, setClassName] = useState(null)
return (
<AccordionItem className={`accordionItem ${className}`} key={i} uuid={i}>
<AccordionItemHeading>
<AccordionItemButton className='accordionButton flexCenter'>
<AccordionItemState>
{({ expanded }) =>
expanded
? setClassName("expanded")
: setClassName("collapsed")
}
</AccordionItemState>
<div className="icon flexCenter">{item.icon}</div>
<span className="primaryText">
{item.heading}
</span>
<div className="icon flexCenter">
<MdOutlineArrowDropDown size={20} />
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel>
<p className='secondaryText'>{item.detail}</p>
</AccordionItemPanel>
</AccordionItem>
);
})}
</Accordion>
</div>
</div>
</section>
);
};
export default Value;
Value.css
.v-container .image-container {
border: 8px solid #eeeeff;
}
.v-container>div {
flex: 1;
}
.v-right {
gap: 0.5rem;
}
.accordion {
margin-top: 2rem;
border: none;
}
.accordionItem {
background: white;
border: 0.8px solid rgba(128, 128, 128, 0.143);
border-radius: 8px;
overflow: hidden;
margin-bottom: 20px;
}
.accordionItem.expanded {
box-shadow: var(--shadow);
border-radius: 6px;
}
.accordionButton {
background: white;
padding: 1rem;
width: 100%;
justify-content: space-between;
cursor: pointer;
}
.icon {
padding: 10px;
background: #eeeeff;
}
.icon svg {
fill: var(--blue);
}
.accordionButton .primaryText {
font-size: 1.1rem;
}
@media (max-width: 1024px) {
.v-container {
flex-direction: column;
}
}
@media (max-width: 786px) {
.accordionButton .primaryText {
font-size: 0.8rem;
}
}
0 Comments