This article guides you through building an engaging Indian tourism app using React, featuring destination exploration, travel experiences, and a visually appealing image carousel. Users can interact with the app and contact through a form, highlighting the beauty of India.
Preview of final output: Let us have a look at how the final output will look like.
Prerequisites:
Approach to create India Tourism Website:
- The app is structured with a navbar for easy navigation, a carousel to showcase beautiful images, and various routes for different sections like destinations and contact forms.
- React Bootstrap components are seamlessly integrated to enhance the overall user experience.
Steps to Create the React App:
Step 1: Set up a new React project: Use the following command to create project:
npx create-react-app india-tourism-app
cd india-tourism-app
Step 2: Install React Router and React Bootstrap for enhanced functionality.
npm install react-router-dom react-bootstrap bootstrap
Step 3: Create DestinationList.js, DestinationDetail.js, ContactForm.js and destination.js under src.
Project Structure:
The updated dependencies in package.json file will look like:
"dependencies": {
"bootstrap": "^5.3.2",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.17.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
Example: Write the following code in respective files.
-
DestinationDetail.js: The code defines a DestinationDetail component displaying details of a destination based on the provided match object and destination data.
- It dynamically fetches the destination details using the destinationId from the URL parameters and renders information such as name, image, description, rating, and best time to visit.
- Additionally, it includes a “Book Now” button (currently without functionality) within a styled container for a clean and consistent presentation of destination details.
-
ContactForm.js: The code defines a ContactForm component using styled components for a styled form container, labels, inputs, textarea, and a submit button.
- It creates a simple contact form with fields for name, email, and message, providing a clean and responsive design.
- The form lacks a submit functionality, and submitting would typically involve integrating with a backend or API to handle the form data.
-
DestinationList.js: The code defines a functional component DestinationList that renders a list of destinations using styled components for styling.
- It utilizes React Router’s Link component to navigate to detailed destination pages and includes a button to add/remove destinations from favorites.
- State is managed using the useState hook, keeping track of favorite destinations based on user interaction.
- destination.js: The code defines an array of travel destinations, each represented by an object with properties like id, name, description, image, rating, and bestTime.
// App.js import React from 'react' ;
import { BrowserRouter as Router,
Routes, Route as RouteElement,
Link
} from 'react-router-dom' ;
import { Navbar, Nav,
NavDropdown, Carousel
} from 'react-bootstrap' ;
import DestinationList from './components/DestinationList' ;
import DestinationDetail from './components/DestinationDetail' ;
import ContactForm from './components/ContactForm' ;
// Import the custom CSS file import './App.css' ;
const App = () => { return (
<Router>
<div>
<Navbar className= "custom-navbar" expand= "lg" >
<Navbar.Brand className= "brand-heading" >
INCREDIBLE INDIA
</Navbar.Brand>
<Navbar.Toggle aria-controls= "basic-navbar-nav" />
<Navbar.Collapse id= "basic-navbar-nav" >
<Nav className= "ml-auto" >
<Link to= "/" className= "nav-link" >
Home
</Link>
<Link to= "/contact"
className= "nav-link" >
Contact
</Link>
<NavDropdown title= "Explore"
id= "basic-nav-dropdown" >
<Link to= "/travel"
className= "dropdown-item" >
Travel
</Link>
<Link to= "/destinations"
className= "dropdown-item" >
Destinations
</Link>
<Link to= "/experience"
className= "dropdown-item" >
Experience
</Link>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
{ /* Carousel */ }
<Carousel className= "custom-carousel" >
<Carousel.Item>
<img
className= "d-block w-100 carousel-image"
src=
alt= "First slide" />
</Carousel.Item>
<Carousel.Item>
<img
className= "d-block w-100 carousel-image"
src=
alt= "Second slide" />
</Carousel.Item>
<Carousel.Item>
<img
className= "d-block w-100 carousel-image"
src=
alt= "Third slide" />
</Carousel.Item>
<Carousel.Item>
<img
className= "d-block w-100 carousel-image"
src=
alt= "Fourth slide" />
</Carousel.Item>
</Carousel>
<br />
{ /* Content of your app (unchanged) */ }
<Routes>
<RouteElement path= "/"
element={<DestinationList />} />
<RouteElement path= "/destination/:id"
element={<DestinationDetail />} />
<RouteElement path= "/contact"
element={<ContactForm />} />
{ /* Add routes for travel, destinations, and experience */ }
</Routes>
{ /* Footer */ }
<div className= "custom-footer" >
<div className= "footer-section" >
<h3>Connect with us</h3>
<ul className= "social-links" >
target= "_blank"
rel= "noopener noreferrer" >
Facebook
</a>
</li>
target= "_blank"
rel= "noopener noreferrer" >
Twitter
</a>
</li>
target= "_blank"
rel= "noopener noreferrer" >
Instagram
</a>
</li>
</ul>
</div>
<div className= "footer-section" >
<h3>Contact us</h3>
<p>Email: contact@incredibleindia.com</p>
<p>Phone: +91 123 456 7890</p>
</div>
<div className= "footer-section" >
<h3>Newsletter</h3>
<p>
Subscribe to our newsletter
for updates and offers.
</p>
<form>
<input type= "email" placeholder= "Your email" />
<button type= "submit" >Subscribe</button>
</form>
</div>
</div>
</div>
</Router>
);
} export default App;
|
// DestinationDetail.js import React from 'react' ;
import styled from 'styled-components' ;
import destinations from './Destinations' ;
const DetailContainer = styled.div` max-width: 600px;
margin: auto;
`; const DetailImage = styled.img` width: 100%;
height: auto;
border-radius: 8px;
margin-bottom: 20px;
`; const DetailButton = styled.button` background: #3498db;
color: #fff;
border: none;
padding: 10px;
border-radius: 4px;
cursor: pointer;
`; const DestinationDetail = ({ match }) => { const destinationId =
parseInt(match.params.id);
const destination =
destinations.find(
dest =>
dest.id === destinationId
);
if (!destination) {
return <div style={
{
textAlign: 'center'
}}>
Destination not found
</div>;
}
return (
<DetailContainer>
<h2>{destination.name}</h2>
<DetailImage src={destination.image}
alt={destination.name} />
<p>{destination.description}</p>
<p>Rating:
{destination.rating || 'Not available' }
</p>
<p>
Best time to visit:
{destination.bestTime || 'Not specified' }
</p>
<DetailButton>Book Now</DetailButton>
</DetailContainer>
);
}; export default DestinationDetail;
|
// ContactForm.js import React from 'react' ;
import styled from 'styled-components' ;
const ContactContainer = styled.div` max-width: 600px;
margin: auto;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
background-color: #fff;
border-radius: 8px;
margin-top: 50px;
`; const Form = styled.form` display: flex;
flex-direction: column;
`; const Label = styled.label` margin-bottom: 8px;
`; const Input = styled.input` padding: 10px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
`; const TextArea = styled.textarea` padding: 10px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
`; const SubmitButton = styled.button` background-color: #3498db;
color: #fff;
padding: 12px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
`; const ContactForm = () => { return (
<ContactContainer>
<h2>Contact Us</h2>
<Form>
<Label htmlFor= "name" >
Name
</Label>
<Input type= "text"
id= "name"
name= "name" required />
<Label htmlFor= "email" >
Email
</Label>
<Input type= "email"
id= "email"
name= "email" required />
<Label htmlFor= "message" >
Message
</Label>
<TextArea id= "message"
name= "message"
rows= "4" required />
<SubmitButton type= "submit" >
Submit
</SubmitButton>
</Form>
</ContactContainer>
);
}; export default ContactForm;
|
// DestinationList.js import React, { useState } from 'react' ;
import { Link } from 'react-router-dom' ;
import styled from 'styled-components' ;
import destinations from './Destinations' ;
const List = styled.ul` list-style: none;
padding: 0;
display: flex;
justify-content: space-around;
flex-wrap: wrap;
`; const ListItem = styled.li` margin-bottom: 20px;
text-align: center;
`; const Image = styled.img` width: 100%;
height: auto;
border-radius: 8px;
`; const Button = styled.button` background: #3498db;
color: #fff;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
`; const DestinationList = () => { const [favorites, setFavorites] = useState([]);
const toggleFavorite = (id) => {
if (favorites.includes(id)) {
setFavorites(
favorites
.filter(favId =>
favId !== id)
);
} else {
setFavorites([...favorites, id]);
}
};
return (
<div style={
{
backgroundColor: "#c8e2fa" ,
padding: "2%"
}
}>
<List>
{destinations.map((destination) => (
<ListItem key={destination.id}>
<Link to={`/destination/${destination.id}`}
style={
{
textDecoration: 'none' ,
color: '#333'
}}>
<Image src={destination.image}
alt={destination.name} />
<h3>{destination.name}</h3>
<h5>{destination.bestTime}</h5>
<h6>{destination.rating}</h6>
</Link>
<Button onClick={
() =>
toggleFavorite(destination.id)
}>
{
favorites.includes(destination.id) ?
'Remove from Favorites' :
'Add to Favorites'
}
</Button>
</ListItem>
))}
</List>
</div>
);
}; export default DestinationList;
|
// Destinations.js const Destinations = [ {
id: 1,
name: 'Taj Mahal' ,
description: 'A symbol of love...' ,
image:
rating: 4.5,
bestTime: 'October to February'
},
// Add more destinations
{
id: 2,
name: 'Jaipur City Palace' ,
description: 'A magnificent palace...' ,
image:
rating: 4.5,
bestTime: 'October to February' ,
},
// 18 more destinations...
{
id: 3,
name: 'Goa Beaches' ,
description: 'Beautiful sandy beaches...' ,
image:
rating: 4.6,
bestTime: 'November to February' ,
},
{
id: 4,
name: 'Kerala Backwaters' ,
description: 'Scenic beauty of backwaters...' ,
image:
rating: 4.7,
bestTime: 'September to March' ,
},
{
id: 5,
name: 'Hampi Ruins' ,
description: 'Ancient ruins and temples...' ,
image:
rating: 4.4,
bestTime: 'October to March' ,
},
{
id: 6,
name: 'Rishikesh Yoga Retreats' ,
description: 'Peaceful yoga retreats...' ,
image:
rating: 4.9,
bestTime: 'September to November' ,
},
{
id: 7,
name: 'Darjeeling Tea Gardens' ,
description: 'Lush green tea gardens...' ,
image:
rating: 4.5,
bestTime: 'March to November' ,
},
{
id: 8,
name: 'Mysore Palace' ,
description: 'Historical royal palace...' ,
image:
rating: 4.6,
bestTime: 'October to February' ,
},
{
id: 9,
name: 'Rann of Kutch' ,
description: 'Endless white salt desert...' ,
image:
rating: 4.7,
bestTime: 'October to March' ,
},
{
id: 10,
name: 'Varanasi Ghats' ,
description: 'Sacred river ghats...' ,
image:
rating: 4.8,
bestTime: 'October to March' ,
},
{
id: 11,
name: 'Andaman Islands' ,
description: 'Exotic islands and beaches...' ,
image:
rating: 4.6,
bestTime: 'October to April' ,
},
{
id: 12,
name: 'Udaipur Lakes' ,
description: 'Picturesque lakes and palaces...' ,
image:
rating: 4.7,
bestTime: 'September to March' ,
},
{
id: 13,
name: 'Ajanta and Ellora Caves' ,
description: 'Ancient rock-cut caves...' ,
image:
rating: 4.8,
bestTime: 'October to March' ,
},
]; export default Destinations;
|
/* App.css */ .custom-navbar { background-color : #7fccff ;
padding : 10px 20px ;
} .brand-heading { font-size : 24px ;
font-weight : bold ;
color : #fff ;
text-decoration : none ;
} .nav-link, .dropdown-item { color : #333 ;
text-decoration : none ;
margin : 0 15px ;
} .nav-link:hover, .dropdown-item:hover { color : #fff ;
} .custom-carousel { margin-top : 20px ;
} .carousel-image { height : 400px ;
object-fit: cover;
} /* App.css */ /* ... Existing styles (unchanged) */ .custom-carousel { margin-top : 20px ;
} .carousel-image { height : 400px ;
object-fit: cover;
} .custom-footer { background-color : #333 ;
color : #fff ;
padding : 20px ;
display : flex;
justify- content : space-around;
align-items: flex-start;
flex-wrap: wrap;
} .footer-section { flex: 1 1 300px ;
margin : 10px ;
} .footer-section h 3 {
font-size : 18px ;
} .social-links { list-style : none ;
padding : 0 ;
} .social-links li { margin-bottom : 8px ;
} .social-links a { text-decoration : none ;
color : #fff ;
} .social-links a:hover { text-decoration : underline ;
} form { display : flex;
flex- direction : column;
} input { margin-bottom : 10px ;
padding : 8px ;
} button { background-color : #3498db ;
color : #fff ;
border : none ;
padding : 10px ;
cursor : pointer ;
} button:hover { background-color : #2980b9 ;
} /* App.css */ /* ... Existing styles (unchanged) */ .custom-carousel { margin-top : 20px ;
} .carousel-image { height : 400px ;
object-fit: cover;
} .custom-footer { background-color : #333 ;
color : #fff ;
padding : 20px ;
display : flex;
justify- content : space-around;
align-items: flex-start;
flex-wrap: wrap;
} .footer-section { flex: 1 1 300px ;
margin : 10px ;
} .footer-section h 3 {
font-size : 18px ;
} .social-links { list-style : none ;
padding : 0 ;
} .social-links li { margin-bottom : 8px ;
} .social-links a { text-decoration : none ;
color : #fff ;
} .social-links a:hover { text-decoration : underline ;
} form { display : flex;
flex- direction : column;
} input { margin-bottom : 10px ;
padding : 8px ;
} button { background-color : #3498db ;
color : #fff ;
border : none ;
padding : 10px ;
cursor : pointer ;
} button:hover { background-color : #2980b9 ;
} |
Step: Run the app with below command:
npm start
Output: