In This tutorial, we will build a beautiful responsive app in 30 Minutes using svelte.
Let's look at the design we are going to build.
I have divided the page into 7 components and these 7 components are the child of App component as shown below.
Let's setup our project called digital_agency_using_svelte. Go to terminal, you can instantly create a new project by running the following command.
npx degit sveltejs/template digital_agency_using_svelte
cd digital_agency_using_svelte
npm install
Adding Bootstrap and fontawesome to the project
For this demo, i am using the following CDN and adding these files to the index.html
that is available under the public folder.
<!--Bootstrap.css-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"crossorigin="anonymous">
<!--fontawesome.js-->
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>
<!--Slim.js-->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<!--bootstrap.js-->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
Adding global styles to the project.
You can add the following css to the global.css
that is available under the public folder.
/**public/global.css**/
:root {
--gradient: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
--light: #fff;
--grey: #f8f9fa;
}
html,
body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
scroll-behavior: smooth;
}
.main-bgcolor {
background-image: var(--gradient);
}
.light-color {
color: var(--light) !important;
}
.grey-bgcolor {
background: var(--grey);
}
.company_brand {
font-size: x-large;
font-family: cursive;
}
.section {
padding: 50px 0;
}
.section-body {
padding: 20px 0;
}
Adding static Data to the project.
I have created a JSON of static data that is used in the project. Create a Data
folder inside the src
folder and under the Data
folder create a file data.js
. Add the following static data to it.
/**src/Data/data.js**/
const HEADER = "Nixalar";
const NAVBAR_DATA = [
{ id: 1, url: "/", label: "Home" },
{ id: 2, url: "#services", label: "Services" },
{ id: 3, url: "#about-us", label: "About us" },
{ id: 4, url: "#testimonials", label: "Testimonials" },
{ id: 5, url: "#footer", label: "Contacts" }
];
const BANNER_DATA = {
HEADING: "Go digital with nixalar",
DECRIPTION:
"Nixalar can help you skyrocket the ROI of your marketing campaign without having to spend tons of money or time to assemble an in-house team.",
TUTORIAL_URL:
"https://www.thinkwithgoogle.com/intl/en-gb/marketing-resources/programmatic/google-digital-academy/",
WATCH_TUTORIAL: "Watch Tutorials"
};
const SERVICE_DATA = {
HEADING: "Our Services",
ALL_SERVICES: "All Services",
SERVICE_LIST: [
{
LABEL: "Search Engine Optimisation",
DESCRIPTION:
"To customise the content, technical functionality and scope of your website so that your pages show for a specific set of keyword at the top of a search engine list. In the end, the goal is to attract traffic to your website when they are searching for goods, services or business-related information.",
URL: "images/service1.png"
},
{
LABEL: "Content Marketing Strategy",
DESCRIPTION:
"It is tough but well worth the effort to create clever material that is not promotional in nature, but rather educates and inspires. It lets them see you as a reliable source of information by delivering content that is meaningful to your audience.",
URL: "images/service2.png"
},
{
LABEL: "Develop Social Media Strategy",
DESCRIPTION:
"Many People rely on social networks to discover, research, and educate themselves about a brand before engaging with that organization. The more your audience wants to engage with your content, the more likely it is that they will want to share it.",
URL: "images/service3.png"
}
]
};
const ABOUT_DATA = {
HEADING: "Why choose us?",
TITLE: "Why we're different",
IMAGE_URL: "images/network.png",
WHY_CHOOSE_US_LIST: [
"We provides Cost-Effective Digital Marketing than Others.",
"High customer statisfaction and experience.",
"Marketing efficiency and quick time to value.",
"Clear & transparent fee structure.",
"We provides Marketing automation which is an integral platform that ties all of your digital marketing together.",
"A strong desire to establish long lasting business partnerships.",
"Provide digital marketing to mobile consumer.",
"We provides wide range to services in reasonable prices"
]
};
const TESTIMONIAL_DATA = {
HEADING: "What clients say?",
TESTIMONIAL_LIST: [
{
DESCRIPTION:
"Nixalar has made a huge difference to our business with his good work and knowledge of SEO and business to business marketing techniques. Our search engine rankings are better than ever and we are getting more people contacting us thanks to Jomer’s knowledge and hard work.",
IMAGE_URL: "images/user1.jpg",
NAME: "Julia hawkins",
DESIGNATION: "Co-founder at ABC"
},
{
DESCRIPTION:
"Nixalar and his team have provided us with a comprehensive, fast and well planned digital marketing strategy that has yielded great results in terms of content, SEO, Social Media. His team are a pleasure to work with, as well as being fast to respond and adapt to the needs of your brand.",
IMAGE_URL: "images/user2.jpg",
NAME: "John Smith",
DESIGNATION: "Co-founder at xyz"
}
]
};
const SOCIAL_DATA = {
HEADING: "Find us on social media",
IMAGES_LIST: [
"images/facebook-icon.png",
"images/instagram-icon.png",
"images/whatsapp-icon.png",
"images/twitter-icon.png",
"images/linkedin-icon.png",
"images/snapchat-icon.png"
]
};
const FOOTER_DATA = {
DESCRIPTION:
"We are typically focused on result-based maketing in the digital world. Also, we evaluate your brand’s needs and develop a powerful strategy that maximizes profits.",
CONTACT_DETAILS: {
HEADING: "Contact us",
ADDRESS: "La trobe street docklands, Melbourne",
MOBILE: "+1 61234567890",
EMAIL: "nixalar@gmail.com"
},
SUBSCRIBE_NEWSLETTER: "Subscribe newsletter",
SUBSCRIBE: "Subscribe"
};
const MOCK_DATA = {
HEADER,
NAVBAR_DATA,
BANNER_DATA,
SERVICE_DATA,
ABOUT_DATA,
TESTIMONIAL_DATA,
SOCIAL_DATA,
FOOTER_DATA
};
export default MOCK_DATA;
Adding Images to the project.
In this project, we have used many images. so, first create an images
folder under the public
folder and download the images from the following Link and add the images to the images
folder Images Link
*Before creating the components create a Components
folder inside the src
folder. *
Navbar component
Create a folder Navbar
inside the components folder and within that create a file Navbar.svelte
. Add the following code to it.
<!--src/Components/Navbar/Navbar.svelte-->
<script>
export let navlists = [];
export let header;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="nav-bar">
<nav class="navbar main-bgcolor navbar-expand-md navbar-dark">
<a class="navbar-brand company_brand" href="/">
{header}
</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon" />
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
{#each navlists as list}
<li class="nav-item">
<a class="nav-link light-color" href={list.url}>{list.label}</a>
</li>
{/each}
</ul>
</div>
</nav>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
#nav-bar {
position: sticky;
top: 0;
z-index: 10;
}
.navbar {
padding: 0 20px !important;
}
.navbar-nav li {
padding: 0 0 0 20px;
}
.navbar-nav li a {
font-weight: 600;
text-transform: uppercase;
float: right;
text-align: left;
}
</style>
In Navbar
component we are using the navlists
and header
that will be pass through the parent component(App.svelte).
Banner component
Create a folder Banner
inside the components folder and within that create a file Banner.svelte
. Add the following code to it.
<!--src/Components/Banner/Banner.svelte-->
<script>
export let bannerData = {};
const { HEADING, DECRIPTION, TUTORIAL_URL, WATCH_TUTORIAL } = bannerData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section class="main-bgcolor light-color" id="banner">
<div class="container">
<div class="row">
<div class="col-md-6">
<h1>{HEADING}</h1>
<p>{DECRIPTION}</p>
<a href={TUTORIAL_URL} target="_blank" class="light-color">
<i class="far fa-play-circle fa-2x watch-btn" />
{WATCH_TUTORIAL}
</a>
</div>
<div class="col-md-6">
<img src="images/home.png" alt="" class="img-fluid" />
</div>
</div>
</div>
<img src="images/wave1.png" alt="" class="wave-img" />
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
section {
padding-top: 5%;
}
h1 {
font-size: 40px;
font-weight: 600;
margin-top: 100px;
text-transform: uppercase;
}
.watch-btn {
margin: auto 20px;
position: relative;
top: 8px;
}
section a {
text-decoration: none;
}
.wave-img {
width: 100%;
height: auto;
}
</style>
In Banner
component we are using the bannerData
that will be pass through the parent component(App.svelte).
Services component
Create a folder Services
inside the components folder and within that create a file Services.svelte
. Add the following code to it.
<!--src/Components/Services/Services.svelte-->
<script>
export let serviceData = {};
const { HEADING, ALL_SERVICES, SERVICE_LIST } = serviceData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="services" class="section">
<div class="container text-center">
<h2 class="title">{HEADING}</h2>
<div class="row section-body">
{#each SERVICE_LIST as list}
<div class="col-md-4 service">
<img src={list.URL} alt={list.LABEL} class="service-img" />
<h4>{list.LABEL}</h4>
<p>{list.DESCRIPTION}</p>
</div>
{/each}
</div>
<buttom class="btn btn-primary round-border main-bgcolor">
{ALL_SERVICES}
</buttom>
</div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
.service-img {
width: 200px;
height: 200px;
margin-top: 20px;
}
.service h4 {
padding: 5px;
margin-top: 25px;
text-transform: uppercase;
}
.title {
text-transform: uppercase;
}
.title::before {
content: "";
background: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
height: 5px;
width: 200px;
margin-left: auto;
margin-right: auto;
display: block;
transform: translateY(60px);
}
.title::after {
content: "";
background: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
height: 10px;
width: 50px;
margin-left: auto;
margin-right: auto;
margin-bottom: 40px;
display: block;
transform: translateY(14px);
}
section .btn-primary {
box-shadow: none;
padding: 8px 25px;
border: none;
}
</style>
In Services
component we are using the serviceData
that will be pass through the parent component(App.svelte).
About component
Create a folder About
inside the components folder and within that create a file About.svelte
. Add the following code to it.
<!--src/Components/About/About.svelte-->
<script>
export let aboutData = {};
const { HEADING, TITLE, IMAGE_URL, WHY_CHOOSE_US_LIST } = aboutData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="about-us" class="section grey-bgcolor">
<div class="container">
<h2 class="title text-center">{HEADING}</h2>
<div class="row section-body">
<div class="col-md-6">
<h3 class="about-title">{TITLE}</h3>
<ul>
{#each WHY_CHOOSE_US_LIST as list}
<li>{list}</li>
{/each}
</ul>
</div>
<div class="col-md-6">
<img src={IMAGE_URL} alt="" class="img-fluid" />
</div>
</div>
</div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
.about-title {
margin-top: 8%;
margin-bottom: 20px;
}
section ul li {
margin: 10px 0;
}
section ul {
padding-left: 23px;
}
</style>
In About
component we are using the aboutData
that will be pass through the parent component(App.svelte).
Testimonials component
Create a folder Testimonials
inside the components folder and within that create a file Testimonials.svelte
. Add the following code to it.
<!--src/Components/Testimonials/Testimonials.svelte-->
<script>
export let testimonialData = {};
const { HEADING, TESTIMONIAL_LIST } = testimonialData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="testimonials" class="section">
<div class="container">
<h2 class="title text-center">{HEADING}</h2>
<div class="row offset-1 section-body">
{#each TESTIMONIAL_LIST as list}
<div class="col-md-5 testimonial">
<p>{list.DESCRIPTION}</p>
<img src={list.IMAGE_URL} alt="" />
<p class="user-details">
<b>{list.NAME}</b>
<br />
{list.DESIGNATION}
</p>
</div>
{/each}
</div>
</div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
.testimonial {
border-left: 4px solid #0072ff80;
margin-top: 10px;
margin-bottom: 10px;
}
.testimonial img {
height: 60px;
width: 60px;
border-radius: 50%;
margin: 0 10px;
}
.user-details {
display: inline-block;
font-size: 12px;
}
</style>
In Testimonials
component we are using the testimonialData
that will be pass through the parent component(App.svelte).
Social component
Create a folder Social
inside the components folder and within that create a file Social.svelte
. Add the following code to it.
<!--src/Components/Social/Social.svelte-->
<script>
export let socialData = {};
const { IMAGES_LIST, HEADING } = socialData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="social-media" class="section grey-bgcolor">
<div class="container text-center">
<h2 class="title text-center">{HEADING}</h2>
<div class="social-icons section-body">
{#each IMAGES_LIST as list}
<a
href="https://www.linkedin.com/in/nikhil-karkra-73a15319/"
target="_blank">
<img src={list} alt="Social media {list}" />
</a>
{/each}
</div>
</div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
.social-icons img {
width: 75px;
transition: 0.5s;
}
.social-icons a:hover img {
transform: translateY(-10px);
}
a:hover {
text-decoration: none;
}
</style>
In Social
component we are using the socialData
that will be pass through the parent component(App.svelte).
Footer component
Create a folder Footer
inside the components folder and within that create a file Footer.svelte
. Add the following code to it.
<!--src/Components/Footer/Footer.svelte-->
<script>
export let footerData = {};
export let header = "";
const {
DESCRIPTION,
CONTACT_DETAILS,
SUBSCRIBE_NEWSLETTER,
SUBSCRIBE
} = footerData;
const { HEADING, ADDRESS, MOBILE, EMAIL } = CONTACT_DETAILS;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section class="main-bgcolor light-color" id="footer">
<img src="images/wave2.png" alt="" class="wave-img" />
<div class="container">
<div class="row section-body">
<div class="col-md-4 footer-box">
<div class="company_brand">{header}</div>
<p>{DESCRIPTION}</p>
</div>
<div class="col-md-4 footer-box">
<p class="footer-title">{HEADING}</p>
<p>
<i class="fas fa-map-marker-alt" />
{ADDRESS}
</p>
<p>
<i class="fas fa-phone" />
{MOBILE}
</p>
<p>
<i class="fas fa-envelope" />
{EMAIL}
</p>
</div>
<div class="col-md-4 footer-box">
<p class="footer-title">{SUBSCRIBE_NEWSLETTER}</p>
<input
type="email"
class="form-control round-border"
placeholder="Your Email" />
<button type="button" class="btn btn-outline-light round-border">
{SUBSCRIBE}
</button>
</div>
</div>
</div>
</section>
<!------------------------------------------->
<!----------------Style----------------------->
<!------------------------------------------->
<style>
.footer-title {
font-weight: bold;
text-transform: uppercase;
}
.footer-box button {
margin-top: 30px;
}
.round-border {
border-radius: 20px !important;
}
.wave-img {
width: 100%;
height: auto;
}
</style>
In Footer
component, we are using the footerData
and header
that will be pass through the parent component(App.svelte).
Adding Child components to Parent (App.svelte)
Till now we are ready with our Child components. Let's add them to App.Svelte
.
Go to App.Svelte
replace the existing code with the below code.
<!--src/App.svelte-->
<script>
import Navbar from "./Components/Navbar/Navbar.svelte";
import Banner from "./Components/Banner/Banner.svelte";
import Services from "./Components/Services/Services.svelte";
import About from "./Components/About/About.svelte";
import Testimonials from "./Components/Testimonials/Testimonials.svelte";
import Social from "./Components/Social/Social.svelte";
import Footer from "./Components/Footer/Footer.svelte";
import DATA from "./Data/data";
</script>
<!-- Navbar -->
<Navbar navlists={DATA.NAVBAR_DATA} header={DATA.HEADER} />
<!-- Banner -->
<Banner bannerData={DATA.BANNER_DATA} } />
<!-- Services -->
<Services serviceData={DATA.SERVICE_DATA} />
<!-- About -->
<About aboutData={DATA.ABOUT_DATA} />
<!-- Testimonials -->
<Testimonials testimonialData={DATA.TESTIMONIAL_DATA} />
<!-- Social Media -->
<Social socialData={DATA.SOCIAL_DATA} />
<!-- Footer -->
<Footer footerData={DATA.FOOTER_DATA} header={DATA.HEADER} />
If you look at the code above. We are passing the props to the each component wherever it's required. We are ideally passing the static data that we created in Data/data.js
.
Run the project
Now our project is ready. let's run the project using the following command.
run dev
Go to http://localhost:5000/. You will see the following output
Code and reference
I have deployed it to now
https://nixalar-digital-agency.now.sh/
Github
https://github.com/karkranikhil/Digital-Agency-using-svelte
Top comments (17)
This is not directly related to Svelte; but I'm seeing a trend where websites like this with almost purely static content are written in frontend frameworks like Svelte, Vue, React or Angular while they don't need the overhead.
Websites like this should just be plain HTML files, some CSS sprinkled in and no Javascript.
Would love to know, time taken to build in HTML/css only and what the mobile score would be on a page like that? 👍🏻👍🏻
It will take less time in case no frameworks used.
It will also requires less qualificated labor.
Framework == high mobile score ? Rubbish. Exactly opposite
I agree with you this demo is more of HTML and CSS but Svelte is not a framework or library it's a Compiler. So at the end everything is plain JS.
I agree. I haven't seen the first tutorial who actually makes use of the real benefits of using svelte. Besides from the official docs.
I agree Svelte actual use case comes when we have Single page application where i can reuse my components. But with the same demo i can achieve better page speed and SEO. Svelte is a compiler; it compiles components into JavaScript. SO bundle size is very less compare to other lib and frameworks
Thank you for this. I'm just getting started with Svelte, and while I see comments saying this "should" be done in pure HTML and CSS, I needed to see how this much could be done in Svelte and how Svelte components might be organized -- and above all how to add bootstrap!
github.com/bestguy/sveltestrap
You can use sveltestrap. I have used the CDN of Bootstrap. You can download the bootstrap and place it under public folder and give the same path in index.html
Thank you for sharing your tutorial. The finished product looks great. I analyzed the completed page, using the link you provided, with Google Pagespeed and found that the mobile score was only 76, and that some easy optimizations could be made.
Yeah we can improve this..once I LL get time I LL do it.
Fantastic. This is what I love about Svelte and you showed a great representation of how to use Svelte and its practicality for simpler but truly dynamic and re-usable code.
Svelte truly is a designers toolset and absolutely capable of very complex application logic.
Great job!!
I have a question on style for you.
If you wanted to split the 'About' page out onto it's own page, would the route be to a static file in PUBLIC (e.g. about.html) or to another svelte component and how could the Nav bar be reused in that case?
If you don't want to load the whole CSS framework, you can load it in with node-sass in your package bundler and use a styles.scss file. Example of that for Bulma is:
// Import only what you need from Bulma
@import "../node_modules/bulma/sass/utilities/_all.sass";
@import "../node_modules/bulma/sass/base/_all.sass";
@import "../node_modules/bulma/sass/components/_all.sass";
@import "../node_modules/bulma/sass/elements/_all.sass";
@import "../node_modules/bulma/sass/form/_all.sass";
@import "../node_modules/bulma/sass/grid/_all.sass";
@import "../node_modules/bulma/sass/layout/_all.sass";
If your goal is to slow down browser rendering speed - yes, it is great idea. Instead of loading and rendering static html page browser should load index.html, than load, parse and execute js bundle, and at the end the user will see some content.
It will be much better to apply your vision with sapper and data in json format
Awesome!
wow this is nice and practical, love it.