Create a book publishing website template using HTML, CSS (Bootstrap 5), and JavaScript. Step-by-step guide with code, perfect for beginners.
Table of Contents
Want to create your own book publishing website? Whether you're an author or a web developer, building a site using HTML, CSS (Bootstrap 5), and JavaScript is a great idea. In this blog, we will help you design a beautiful book publishing website template step-by-step.
Prerequisites:
Before we begin, make sure you have the following:
- A basic understanding of HTML, CSS, and JavaScript
- A code editor like VS Code
- A modern web browser (Chrome, Firefox, etc.)
- Bootstrap 5 CDN links (we will provide them below)
Source Code
Step 1 (HTML Code):
First, we will start with the HTML part. Here, we will create the layout of the website and use Bootstrap 5 for a responsive design. We’ll also use the Swiper plugin to make a smooth carousel for book slides.
Copy and paste the HTML code below into your index.html file:
Step 2 (CSS Code):
After HTML, let’s move to the CSS part. Even though Bootstrap covers a lot of styling, we still need some custom CSS to make our design look better.
Copy and paste the CSS code below into your styles.css file:
/* General Styles */
body {
font-family: 'Inter', sans-serif;
color: #333;
line-height: 1.7;
background-color: #f8f9fa;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Merriweather', serif;
font-weight: 700;
color: #2c3e50;
}
.lead {
font-family: 'Lora', serif;
font-size: 1.25rem;
font-weight: 400;
}
.btn-primary {
background-color: #3498db;
border-color: #3498db;
transition: background-color 0.3s ease, border-color 0.3s ease, transform 0.2s ease;
padding: 0.75rem 1.5rem;
font-weight: 500;
border-radius: 0.375rem;
}
.btn-primary:hover {
background-color: #2980b9;
border-color: #2980b9;
transform: translateY(-2px);
}
.btn-outline-primary {
color: #3498db;
border-color: #3498db;
transition: background-color 0.3s ease, color 0.3s ease, transform 0.2s ease;
padding: 0.75rem 1.5rem;
font-weight: 500;
border-radius: 0.375rem;
}
.btn-outline-primary:hover {
background-color: #3498db;
color: #fff;
transform: translateY(-2px);
}
.btn-outline-light:hover {
transform: translateY(-2px);
}
.section-padding {
padding: 80px 0;
}
.section-title {
margin-bottom: 60px;
text-align: center;
}
.section-title h2 {
font-size: 2.5rem;
position: relative;
padding-bottom: 15px;
}
.section-title h2::after {
content: '';
position: absolute;
display: block;
width: 60px;
height: 3px;
background: #3498db;
bottom: 0;
left: calc(50% - 30px);
}
.navbar {
background-color: #ffffff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding-top: 1rem;
padding-bottom: 1rem;
}
.navbar-brand {
font-family: 'Merriweather', serif;
font-weight: 900;
font-size: 1.8rem;
color: #2c3e50 !important;
}
.navbar-brand i {
color: #3498db;
}
.nav-link {
font-weight: 500;
color: #555 !important;
margin-left: 10px;
margin-right: 10px;
transition: color 0.3s ease;
}
.nav-link:hover,
.nav-link.active {
color: #3498db !important;
}
/* New Hero Section */
#hero {
min-height: 95vh;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
/* For pseudo-element */
background: #e0eafc;
/* Fallback */
background: linear-gradient(135deg, #e0eafc 0%, #cfdef3 100%);
/* Light, airy gradient */
padding: 100px 0;
}
#hero::before {
/* Subtle background pattern */
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23b2c2df' fill-opacity='0.1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
opacity: 0.5;
z-index: 0;
}
#hero .container {
position: relative;
/* To ensure content is above pseudo-elements */
z-index: 1;
text-align: left;
/* Align text to the left */
}
#hero .hero-content {
max-width: 600px;
/* Limit width of text content */
}
#hero h1 {
font-size: 3.8rem;
/* Slightly larger */
font-weight: 900;
margin-bottom: 25px;
color: #2c3e50;
/* Darker text for better contrast on light bg */
line-height: 1.2;
}
#hero h1 span {
/* For highlighting words */
color: #3498db;
}
#hero p.lead-hero {
/* Custom lead for hero */
font-size: 1.4rem;
font-family: 'Lora', serif;
margin-bottom: 35px;
color: #5a6a7a;
/* Softer dark gray */
}
#hero .hero-image-container {
display: flex;
align-items: center;
justify-content: center;
}
#hero .hero-image-container img {
max-width: 100%;
height: auto;
border-radius: 15px;
box-shadow: 0 15px 35px rgba(44, 62, 80, 0.15);
}
/* Book Card Styles */
.book-card {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
/* Softer shadow */
transition: transform 0.3s ease, box-shadow 0.3s ease;
overflow: hidden;
margin-bottom: 30px;
display: flex;
/* For consistent height in grids/flex containers */
flex-direction: column;
}
.book-card:hover {
transform: translateY(-10px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
}
.book-card img {
width: 100%;
height: auto;
/* Make height auto for better responsiveness */
aspect-ratio: 3 / 4;
/* Maintain aspect ratio */
object-fit: cover;
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
}
.book-card .card-body {
padding: 20px;
flex-grow: 1;
/* Allows card body to fill space */
display: flex;
flex-direction: column;
}
.book-card .card-title {
font-size: 1.3rem;
/* Slightly adjusted */
margin-bottom: 10px;
}
.book-card .card-text {
font-size: 0.9rem;
/* Slightly adjusted */
color: #666;
margin-bottom: 15px;
flex-grow: 1;
}
.book-card .btn-sm {
padding: 0.35rem 0.8rem;
font-size: 0.8rem;
}
.book-card .genre-tag {
display: inline-block;
background-color: #e9ecef;
color: #495057;
padding: 5px 10px;
border-radius: 0.25rem;
font-size: 0.75rem;
/* Slightly smaller */
margin-bottom: 10px;
}
/* Featured Books Carousel (Swiper) */
.featured-books-slider .swiper-slide {
display: flex;
justify-content: center;
align-items: stretch;
/* Make cards in a row same height */
padding-bottom: 10px;
/* Space for shadow on hover */
}
.featured-books-slider .book-card {
width: 100%;
/* Card takes full width of the slide */
height: 100%;
/* Card takes full height of the slide */
}
.swiper-button-next,
.swiper-button-prev {
color: #3498db;
transition: opacity 0.3s ease;
}
.swiper-button-next:hover,
.swiper-button-prev:hover {
opacity: 0.7;
}
.swiper-pagination-bullet-active {
background: #3498db;
}
/* Author Profiles */
.author-card {
text-align: center;
background-color: #fff;
padding: 30px;
border-radius: 0.5rem;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease, box-shadow 0.3s ease;
height: 100%;
/* For consistent height in rows */
}
.author-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
}
.author-card img {
width: 150px;
height: 150px;
border-radius: 50%;
object-fit: cover;
margin-bottom: 20px;
border: 5px solid #e0e0e0;
}
.author-card h5 {
font-size: 1.3rem;
}
/* Genres/Collections */
.nav-pills .nav-link {
background-color: #e9ecef;
color: #495057;
margin: 0 5px 10px;
border-radius: 0.375rem;
transition: background-color 0.3s ease, color 0.3s ease;
}
.nav-pills .nav-link.active {
background-color: #3498db;
color: #fff !important;
}
.nav-pills .nav-link:not(.active):hover {
background-color: #d1d9e0;
}
.genre-content {
padding-top: 20px;
}
/* Testimonials (Swiper) */
.testimonial-slider .swiper-slide {
padding: 25px;
/* Increased padding */
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
text-align: center;
}
.testimonial-slider img {
width: 80px;
height: 80px;
border-radius: 50%;
margin-bottom: 15px;
border: 3px solid #3498db;
/* Added border */
}
.testimonial-slider .stars {
color: #f39c12;
margin-bottom: 10px;
font-size: 1.1rem;
}
.testimonial-slider p {
font-style: italic;
color: #555;
}
/* Events Section */
.event-card {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.07);
padding: 25px;
/* Increased padding */
margin-bottom: 25px;
/* Increased margin */
}
.event-date {
font-size: 1.5rem;
font-weight: 700;
color: #3498db;
display: block;
margin-bottom: 5px;
}
/* Flatpickr specific styling for better integration */
.flatpickr-calendar {
border-radius: 0.375rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
#eventCalendarContainer .flatpickr-calendar {
/* Ensure inline calendar fits well */
width: 100% !important;
box-shadow: none;
border: 1px solid #ddd;
}
/* Blog Section */
.blog-post-card {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.07);
margin-bottom: 30px;
overflow: hidden;
height: 100%;
/* For consistent height in rows */
display: flex;
flex-direction: column;
}
.blog-post-card img {
width: 100%;
height: 220px;
/* Adjusted height */
object-fit: cover;
backface-visibility: hidden;
}
.blog-post-card .card-body {
padding: 25px;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.blog-post-card .card-title {
font-size: 1.4rem;
/* Adjusted */
}
.blog-post-card .card-text {
flex-grow: 1;
}
.blog-post-card .meta {
font-size: 0.85rem;
color: #777;
margin-bottom: 10px;
}
/* Newsletter & Contact Forms */
.form-control {
border-radius: 0.375rem;
padding: 0.75rem 1rem;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.form-control:focus {
border-color: #3498db;
box-shadow: 0 0 0 0.25rem rgba(52, 152, 219, 0.25);
}
/* Footer */
footer {
background-color: #2c3e50;
color: #ecf0f1;
padding: 60px 0 30px;
}
footer h5 {
color: #fff;
margin-bottom: 20px;
font-family: 'Merriweather', serif;
}
footer p,
footer a {
color: #bdc3c7;
font-size: 0.9rem;
}
footer a:hover {
color: #3498db;
text-decoration: none;
}
footer .social-icons a {
color: #bdc3c7;
font-size: 1.5rem;
margin-right: 15px;
transition: color 0.3s ease, transform 0.2s ease;
}
footer .social-icons a:hover {
color: #3498db;
transform: scale(1.1);
}
.footer-bottom {
border-top: 1px solid #34495e;
padding-top: 20px;
margin-top: 30px;
text-align: center;
font-size: 0.85rem;
}
/* Responsive Adjustments */
@media (max-width: 991.98px) {
#hero {
text-align: center;
/* Center hero text on smaller screens */
padding: 80px 0;
}
#hero .hero-content {
margin-left: auto;
margin-right: auto;
}
#hero h1 {
font-size: 2.8rem;
}
#hero p.lead-hero {
font-size: 1.2rem;
}
#hero .hero-image-container {
margin-top: 40px;
}
.section-title h2 {
font-size: 2rem;
}
.navbar-nav {
text-align: center;
background-color: #fff;
padding-bottom: 10px;
margin-top: 10px;
/* Space from toggler */
border-top: 1px solid #eee;
}
.nav-link {
margin-left: 0;
margin-right: 0;
padding: 10px 0;
}
}
@media (max-width: 767.98px) {
#hero {
padding: 60px 0;
min-height: auto;
/* Adjust min height */
}
#hero h1 {
font-size: 2.2rem;
}
#hero p.lead-hero {
font-size: 1.1rem;
}
.book-card img {
aspect-ratio: 4/5;
/* Adjust aspect ratio for smaller screens if needed */
}
.section-padding {
padding: 60px 0;
}
.featured-books-slider .swiper-button-next,
.featured-books-slider .swiper-button-prev {
display: none;
/* Hide arrows on small screens for more space */
}
} Step 3 (JavaScript Code):
This is the final step. Now we will write a small JavaScript function to activate the Swiper carousel. We will place this script inside the script.js file.
Copy and paste the JavaScript code below into your script.js file:
document.addEventListener('DOMContentLoaded', function () {
// Initialize Swiper for Featured Books
const featuredBooksSwiper = new Swiper('.featured-books-slider', {
loop: true,
slidesPerView: 1,
spaceBetween: 20, // Adjusted space
grabCursor: true,
pagination: {
el: '.featured-books-slider .swiper-pagination', // Scoped pagination
clickable: true,
},
navigation: {
nextEl: '.featured-books-slider .swiper-button-next', // Scoped navigation
prevEl: '.featured-books-slider .swiper-button-prev', // Scoped navigation
},
breakpoints: {
576: { // Small devices (landscape phones, 576px and up)
slidesPerView: 2,
spaceBetween: 20
},
768: { // Medium devices (tablets, 768px and up)
slidesPerView: 3,
spaceBetween: 30
},
1200: { // Extra large devices (large desktops, 1200px and up)
slidesPerView: 4,
spaceBetween: 30
}
}
});
// Initialize Swiper for Testimonials
const testimonialSwiper = new Swiper('.testimonial-slider', {
loop: true,
slidesPerView: 1,
spaceBetween: 30,
grabCursor: true,
autoplay: {
delay: 5000,
disableOnInteraction: false,
},
pagination: {
el: '.testimonial-slider .swiper-pagination', // Scoped pagination
clickable: true,
},
breakpoints: {
768: {
slidesPerView: 2,
spaceBetween: 30
},
992: {
slidesPerView: 3,
spaceBetween: 30
}
}
});
// Initialize Flatpickr for Event Calendar
// Option 1: Calendar as a dropdown for the input field
flatpickr("#eventCalendarFlatpickr", {
dateFormat: "Y-m-d",
altInput: true,
altFormat: "F j, Y",
// Example: To mark specific dates as events (you'd fetch these dynamically)
// Add 'enable' option with specific dates if you want to highlight them.
// For example:
// enable: [
// { from: "today", to: new Date().fp_incr(7) }, // Enable next 7 days
// "2025-07-25", // A specific event date
// "2025-08-10" // Another specific event date
// ],
// To show which dates have events, you might need custom styling or a 'dayCreate' hook.
// This basic setup just provides a date picker.
onChange: function (selectedDates, dateStr, instance) {
// You can add logic here if a date is selected, e.g., filter events list
console.log("Date selected for calendar: " + dateStr);
}
});
// Option 2: If you want an inline calendar, uncomment below and ensure #eventCalendarContainer exists
/*
flatpickr("#eventCalendarContainer", {
dateFormat: "Y-m-d",
altInput: false, // No alternate input field needed for inline
inline: true, // Show calendar inline
enable: [
{ from: "today", to: new Date().fp_incr(60) }
],
// Add more configurations as needed
onChange: function(selectedDates, dateStr, instance) {
console.log("Date selected on inline calendar: " + dateStr);
// Potentially update a hidden input or filter events
// document.getElementById('hiddenEventDateInput').value = dateStr;
}
});
*/
// Initialize Vanilla Tilt.js on book cards
VanillaTilt.init(document.querySelectorAll(".vanilla-tilt"), {
max: 8, // Reduced max tilt
speed: 300,
glare: true,
"max-glare": 0.1 // Reduced glare
});
// Newsletter Form Submission with SweetAlert2
const newsletterForm = document.getElementById('newsletterForm');
if (newsletterForm) {
newsletterForm.addEventListener('submit', function (e) {
e.preventDefault();
const emailInput = document.getElementById('newsletterEmail');
const email = emailInput.value;
if (email && emailInput.checkValidity()) { // Added basic HTML5 validation check
// Simulate API call
setTimeout(() => {
Swal.fire({
icon: 'success',
title: 'Subscribed!',
text: 'Thanks for subscribing to our newsletter.',
confirmButtonColor: '#3498db'
});
newsletterForm.reset();
}, 500);
} else {
Swal.fire({
icon: 'error',
title: 'Invalid Email',
text: 'Please enter a valid email address.',
confirmButtonColor: '#3498db'
});
}
});
}
// Contact Form Submission with SweetAlert2
const contactForm = document.getElementById('contactForm');
if (contactForm) {
contactForm.addEventListener('submit', function (e) {
e.preventDefault();
const name = document.getElementById('contactName').value;
const email = document.getElementById('contactEmail').value;
const subject = document.getElementById('contactSubject').value;
const message = document.getElementById('contactMessage').value;
// Basic validation using HTML5 `required` attribute.
// For more complex validation, you'd add more JS checks here.
if (contactForm.checkValidity()) {
// Simulate API call
setTimeout(() => {
Swal.fire({
icon: 'success',
title: 'Message Sent!',
text: 'We have received your message and will get back to you shortly.',
confirmButtonColor: '#3498db'
});
contactForm.reset();
}, 500);
} else {
// If using more complex JS validation, this alert could be more specific.
// For now, relying on browser's default messages for required fields.
Swal.fire({
icon: 'error',
title: 'Incomplete Form',
text: 'Please fill out all required fields correctly.',
confirmButtonColor: '#3498db'
});
}
});
}
// Smooth scrolling for nav links
document.querySelectorAll('a.nav-link[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
const offsetTop = targetElement.offsetTop - 70; // Adjust for fixed navbar height
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
// Close mobile nav if open
const navbarToggler = document.querySelector('.navbar-toggler');
const navbarCollapse = document.querySelector('.navbar-collapse');
if (navbarToggler && navbarCollapse.classList.contains('show')) {
const bsCollapse = bootstrap.Collapse.getInstance(navbarCollapse);
if (bsCollapse) {
bsCollapse.hide();
}
}
}
});
});
// Active nav link highlighting on scroll
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
const navbarHeight = document.querySelector('.navbar').offsetHeight || 70;
function updateActiveNavLink() {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
if (pageYOffset >= (sectionTop - navbarHeight - 10)) { // Adjusted offset
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
// Check if the link's href matches the current section's ID
if (link.getAttribute('href') === `#${current}`) {
link.classList.add('active');
}
});
// Special case for top of page / hero
if (window.pageYOffset < sections[0].offsetTop - navbarHeight - 10) {
navLinks.forEach(link => link.classList.remove('active'));
const homeLink = document.querySelector('.navbar-nav .nav-link[href="#hero"]');
if (homeLink) homeLink.classList.add('active');
}
}
window.addEventListener('scroll', updateActiveNavLink);
updateActiveNavLink(); // Initial call to set active link on page load
// Set current year in footer
document.getElementById('currentYear').textContent = new Date().getFullYear();
});Final Output:
Conclusion:
Creating a book publishing website template using HTML, CSS (Bootstrap 5), and JavaScript is easier than you think. This basic template helps you get started quickly. You can customize it further based on your needs—whether you’re selling books, showcasing novels, or launching a publishing service.
Want to add more features like search filters, categories, or author profiles? You can keep building on this simple base.
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊


