Skip to the article
Aniq-UI

SaaS Landing PageMake it yours

Make it yours

Where to change the name, the text, the images, the prices, the colours, the fonts, the sections and the links.

Run the site with yarn dev while you edit: the page reloads each time you save. Every path below is relative to the landing-page-template-2 folder.

To changeEdit
The brand namename in src/config/site.ts
Any text on the pagemessages/en.json and messages/ar.json
Images and logospublic/ and the constants/ folder of each section
Prices and planssrc/features/home/Pricing/constants/plans.ts and src/features/home/ComparisonTable/constants/
Colourssrc/styles/globals.css and the Tailwind classes in the components
Fontssrc/lib/fonts.ts
Which sections appear, and their ordersrc/app/[locale]/page.tsx
Menu, footer and social linkssrc/layouts/Header/constants/, src/layouts/Footer/constants/footer.ts, src/config/site.ts
The site's address for search engines and sharingNEXT_PUBLIC_SITE_URL

The two settings

VariableDefaultWhat it does
NEXT_PUBLIC_SITE_URLhttp://localhost:3030The public address of the site. The canonical link, the language alternates and the social sharing cards are built from it. Set it to your domain before you go live.
NEXT_PUBLIC_API_BASE_URLemptyThe API that receives newsletter sign-ups. Only used by the newsletter section.

Without Docker, put them in .env.local (copy .env.example). With Docker, pass them as build arguments: the image build does not read .env or .env.local files.

.env.local
NEXT_PUBLIC_SITE_URL=https://www.your-domain.com
Terminalin landing-page-template-2
docker build -t saas-landing --build-arg NEXT_PUBLIC_SITE_URL=https://www.your-domain.com .

Both values are compiled into the page when it is built. After a change, restart yarn dev, run yarn build again, or build the Docker image again. Never put a secret in a NEXT_PUBLIC_ value: every visitor can read it.

The brand name and logo

name in src/config/site.ts is the brand. The logo in the header and the footer is its first letter in a coloured square, followed by the name, drawn by src/components/Logo.tsx. Texts that say {brand} in the message files use it too.

src/config/site.ts
name: "SaasPro",

The same value fills the page title, the social sharing card, the Resources menu and the web app manifest, which src/app/manifest.ts builds in the page's dark colours. You change the name in one place.

creator in the same file is the author named in the page's metadata. Change it too.

Text

Every visible word, every image description and the page title live in messages/en.json and messages/ar.json. Each section has its own block, named after it: Header, Hero, SocialProof, Features, HowItWorks, Testimonials, Pricing, Comparison, Integrations, Faq, Blog, Cta, Newsletter and Footer.

  • Change the value, keep the key, and change it in both files. A key missing from one file shows as a missing-message error on that language's page.
  • Words in curly braces, such as {brand} and {year}, are filled in by the app. Keep them as they are.
  • In HowItWorks.title, the words inside <highlight> and </highlight> are drawn in the gradient colour. Keep both tags.

Images

ImageFileSet in
Hero imagepublic/images/hero.webpsrc/features/home/Hero/constants/hero.ts
How it works, one per steppublic/images/dashboard.png, team.png, webinar.png, automation.pngsrc/features/home/HowItWorks/constants/steps.ts
Header menu picturespublic/images/dashboard.png, webinar.pngsrc/layouts/Header/constants/mega-menus.ts
Company logospublic/images/logos/*.svgsrc/features/home/SocialProof/constants/companies.ts
Integration logospublic/images/logos/*.svgsrc/features/home/Integrations/constants/integrations.ts
Testimonial photosimages.unsplash.comsrc/features/home/Testimonials/constants/testimonials.ts
Blog card imagesimages.unsplash.comsrc/features/home/BlogPreview/constants/articles.ts
Faviconspublic/favicon.svg, favicon.ico, favicon-96x96.png, apple-touch-icon.png, web-app-manifest-*.pngsrc/app/[locale]/layout.tsx, src/app/manifest.ts
Social sharing image, 1200 by 630public/image.pngogImage in src/config/site.ts

The easiest change is to replace a file with your own under the same name. For a new file, put it in public/ and use its path from the site's root, such as /images/your-photo.jpg.

An image from another website only loads if its host is listed under images.remotePatterns in next.config.js. Only images.unsplash.com is listed. Add your host there, or copy the files into public/.

next.config.js
remotePatterns: [
  { protocol: "https", hostname: "images.unsplash.com" },
  { protocol: "https", hostname: "cdn.your-domain.com" },
],

Prices and plans

The prices are in two places, one per section. Change both so they agree:

SectionPrices and featuresText
Pricing cardssrc/features/home/Pricing/constants/plans.ts: price, featureIds and popular per planPricing.plans in the message files
Comparison tablesrc/features/home/ComparisonTable/constants/pricing-tiers.ts for the prices, comparison-features.ts for what each plan includesComparison.tiers and Comparison.features in the message files

A plan's features are listed by id in featureIds, and each id needs its text under the plan in both message files. popular: true marks the plan with the Most Popular badge.

Prices are monthly, in US dollars, formatted for the page's language by src/hooks/usePriceFormatter.ts. To show another currency, change its default currency = "USD" to your currency code, such as "EUR".

Colours

  • The accents: purple and pink Tailwind classes (purple-*, pink-*) in the components, such as from-purple-600 to-pink-500 on the buttons and the logo. Search the src folder for purple- and pink- to change them all.
  • The page background: bg-gray-950 on the page's outer element in src/app/[locale]/page.tsx. The sections use gray-* classes on top of it.
  • The shared button and input: the CSS variables in src/styles/globals.css, such as --primary and --ring. The .dark block is the one in use.

The page is always dark: src/app/[locale]/layout.tsx sets the dark class and starts the theme provider with defaultTheme="dark". There is no light theme or theme switch.

Fonts

src/lib/fonts.ts loads Inter for English and Noto Sans Arabic for Arabic from Google Fonts, through next/font. The fonts are downloaded when the site is built and then served by the site itself. src/app/[locale]/layout.tsx picks the font by language.

src/lib/fonts.ts
import { Inter, Noto_Sans_Arabic } from "next/font/google";

export const inter = Inter({ subsets: ["latin"] });
export const notoSansArabic = Noto_Sans_Arabic({ subsets: ["arabic"] });

To use another Google font, import it from next/font/google in place of one of these and keep the exported name, or change the name where layout.tsx uses it.

Sections

src/app/[locale]/page.tsx lists the sections in the order they appear. Remove a line to hide a section, or move it to change the order. Each section lives in its own folder under src/features/home/.

src/app/[locale]/page.tsx
<Header />
<Hero />
<SocialProof />
<Features />
<HowItWorks />
<Testimonials />
<Pricing />
<ComparisonTable />
<Integrations />
<Faq />
<BlogPreview />
<Cta />
<Footer />

The header links to sections by their id, such as #pricing and #testimonials. If you remove a section, remove its link too.

To add a section:

  1. Create src/features/home/<Section>/ with an index.tsx, and components/ and constants/ folders as the other sections have.
  2. Add its texts under a new key in both message files and read them with useTranslations.
  3. Export it from src/features/home/index.ts and place it in src/app/[locale]/page.tsx.

The newsletter section

A newsletter section with an email form ships in src/features/home/Newsletter/, but it is not on the page. To show it, import it with the others and place it, for example before the call to action:

src/app/[locale]/page.tsx
import {
  …
  BlogPreview,
  Newsletter,
  Cta,
} from "@/features/home";

<BlogPreview />
<Newsletter />
<Cta />

The form needs an API of your own. Set NEXT_PUBLIC_API_BASE_URL to its address; the form sends { "email": "…" } as JSON in a POST to <NEXT_PUBLIC_API_BASE_URL>/newsletter/subscribe, straight from the visitor's browser.

  • A 2xx answer shows the success message and clears the form.
  • Any other answer, a network error, or an empty NEXT_PUBLIC_API_BASE_URL shows the error message. Nothing is sent while the variable is empty.
  • Because the browser sends the request, your API must allow your site's address in its CORS settings.

The texts are under Newsletter in the message files.

Most links in the template point to # until you give them a destination:

LinksEdit
Header links (Pricing, Testimonials)src/layouts/Header/constants/nav-links.ts
Products and Resources menussrc/layouts/Header/constants/mega-menus.ts
Mobile menusrc/layouts/Header/constants/mobile-menu.ts
Footer columnsfooterColumns in src/layouts/Footer/constants/footer.ts
Social icons in the footerlinks in src/config/site.ts
Log in in the headersrc/layouts/Header/components/HeaderActions.tsx
How it works button and step linkssrc/features/home/HowItWorks/components/CtaButton.tsx and StepDetails.tsx
Blog cardssrc/features/home/BlogPreview/components/ArticleCard.tsx

The Get Started, Start Free Trial and Book a Demo buttons, and the buttons on the pricing cards, are plain buttons with no destination. To make one a link, give the Button the asChild prop and put a Link inside it, as src/components/LocaleSwitcher.tsx does:

TypeScript
import { Link } from "@/i18n/navigation";

<Button asChild className="…">
  <Link href="/signup">{common("getStarted")}</Link>
</Button>

The Link from @/i18n/navigation keeps the visitor's language in the address. For another website, use a plain <a href="https://…"> instead.

Dates and the copyright year

  • The footer's copyright year is the year the site was built, from COPYRIGHT_YEAR in src/layouts/Footer/constants/footer.ts. Build again in a new year to update it.
  • Each blog card's date and reading time are publishedAt and readMinutes in src/features/home/BlogPreview/constants/articles.ts; its title and summary are under Blog in the message files.

Search engines and sharing

  • The page title and description are Metadata.title and Metadata.description in each message file, so each language has its own.
  • NEXT_PUBLIC_SITE_URL gives every page its canonical address (/en or /ar) and the links between the two languages. Set it to your domain before you build for production, or search engines and social cards point at localhost.
  • The social sharing card uses public/image.png (1200 by 630) with the same title and description.
  • The template ships no sitemap.xml or robots.txt.

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.