Project logo
Angular 21 landing template

Ship a polished prerendered site instead of a retro control panel.

A cleaner Angular starter for marketing sites and product pages, with SSR-safe prerendering, theme-aware styling, and a layout that feels current in both light and dark mode.

Render mode

Prerender first

Primary output

`dist/app/browser`

UI system

Tailwind + CSS tokens

Theme preview

Light and dark stay aligned

Token-based

Modern rhythm

Clear hierarchy, calmer surfaces, and spacing that reads like a landing page.

Proper theme handling

Surfaces, borders, and accents derive from the shared CSS variables instead of fixed light-only colors.

:root {
  --c-bg-primary;
  --c-bg-secondary;
  --c-text-secondary;
  --c-border;
}

What changed

Less template boilerplate

The page now reads like a product entry point instead of a generated setup checklist.

Styling approach

Tailwind first

Layout, typography, spacing, borders, and most visuals are now driven by utilities tied to the theme tokens.

Visual direction

Sharper and calmer

Brighter focus on hierarchy, restrained gradients, and more premium card treatment in both modes.

Foundation

Built for static-first Angular sites with real deployment discipline.

Keep the app fast, crawlable, and theme-safe without abandoning the Angular patterns this repo already uses.

Angular core

  • Standalone components
  • Signals for UI state
  • OnPush by default
  • Zoneless-ready setup

UI system

  • Tailwind CSS v4
  • Theme variables from `src/styles/_theme.scss`
  • Material Symbols Outlined
  • Component-local SCSS only when needed

Shipping model

  • SSR-compatible app structure
  • Prerendered browser output
  • Static hosting friendly
  • GitHub Pages ready

Shared app layer

  • `wacom` translation bootstrap
  • Theme and language switching
  • Bootstrap data flow
  • SSR-safe service patterns

Workflow

From clone to deploy in a straight line.

1

Start locally

Run the project as a normal Angular dev server while keeping the final target static and prerendered.

2

Build once

Angular generates browser and server artifacts, with static HTML emitted for the prerendered routes.

3

Publish the browser output

Deploy `dist/app/browser` to static hosting and keep the SSR server available only when you actually need it.

Commands

npm start
npm run build
npm run serve:ssr:app

Project map

src/app/pages/
src/app/layouts/
src/app/feature/
src/i18n/
src/styles/

Bootstrap flow

Server data when available, local fallback when not.

  • `APP_INITIALIZER` runs `BootstrapService.initialize()` at startup.
  • Server fetches bootstrap payload and passes it through `TransferState`.
  • Browser applies transferred data immediately and can refresh later.
  • Environment fallbacks keep the site stable when the API is unavailable.

Translations

One translation source, consistent usage patterns.

  • `provideTranslate(...)` initializes the default dictionaries.
  • `src/i18n/*.ts` stays the single source of truth.
  • Use the directive, pipe, or `TranslateService.translate(...)()` where each fits.
  • Language and theme controls stay SSR-safe through the existing app services.

Project structure

Know where the app, SSR, and styles live.

src/
  app/
    app.component.ts
    app.config.ts
    app.config.server.ts
    app.routes.ts
    app.routes.server.ts
    layouts/
    pages/
  assets/
  environments/
  i18n/
  styles/
  styles.scss

SSR configuration lives in `app.config.server.ts` and `app.routes.server.ts`.

Development and build

Run locally, build once, keep SSR optional.

npm start
ng serve
npm run build
npm run serve:ssr:app
node dist/app/server/server.mjs
  • Local development usually runs at `http://localhost:4200` as a normal Angular SPA.
  • `npm run build` generates both `dist/app/browser` and `dist/app/server`.
  • Pages are prerendered at build time using Angular SSR.
  • The Node SSR server exists, but most landing pages only need the prerendered HTML.

Prerender configuration

All routes are prerendered by default.

The default setup in `src/app/app.routes.server.ts` uses `RenderMode.Prerender`, which makes Angular generate static HTML for every route during the build.

RenderMode.Prerender

export const serverRoutes: ServerRoute[] = [
  {
    path: '**',
    renderMode: RenderMode.Prerender,
  },
];

Bootstrap data details

Bootstrap stays SSR-safe while still hydrating from the API when available.

src/app/app.config.ts
src/app/feature/bootstrap/bootstrap.service.ts
src/app/feature/bootstrap/bootstrap.interface.ts
src/app/feature/company/company.service.ts
src/app/feature/item/item.service.ts
src/environments/environment.prod.ts

Server endpoint:

`${environment.apiUrl}/api/regionit/bootstrap/${environment.companyId}`

Payload shape:

export interface BootstrapData {
  company?: Company;
  items?: Item[];
}

  • `APP_INITIALIZER` runs `BootstrapService.initialize()` during startup.
  • Fetched server data is stored in Angular `TransferState`.
  • Browser applies transferred data immediately and then refreshes in the background.
  • If remote data is missing, the app falls back to `environment.company` and `environment.items`.

Environment keys involved

  • `apiUrl` for bootstrap and status checks
  • `companyId` sent to the bootstrap endpoint
  • `company` fallback company data
  • `items` fallback item list
  • `onApiFall` for unavailable API behavior

Current fallback behavior

  • `'app'` keeps rendering with local environment data
  • `'app reload'` polls `${environment.apiUrl}/status` and reloads when API returns

Tailwind and SCSS

Use Tailwind for the routine work, SCSS for the edge cases.

  • Tailwind is configured via `.postcssrc.json`.
  • Prefer utilities for layout, spacing, typography, colors, borders, sizing, and responsive behavior.
  • Use SCSS when Tailwind is not the right tool: complex component styling, tokens, mixins, advanced selectors, or small global layers.
  • Global styles live in `src/styles.scss`.

Recommended split

src/styles.scss
src/app/**/**/*.scss
src/styles/_theme.scss

  • Keep most styles inside the component `.scss` file.
  • Use CSS variables for colors, spacing, and theming.
  • Use `@use`, mixins, and partials for authoring convenience.
  • Avoid deep nesting, `::ng-deep`, and `ViewEncapsulation.None` without a real reason.
  • Prefer class bindings over heavy inline style bindings.

Icons and accessibility

Material Symbols Outlined are the default icon set.

Icons are loaded in `src/index.html`. Keep icons decorative with `aria-hidden="true"` and put text or `aria-label` on the interactive element itself.

<span class="material-symbols-outlined" aria-hidden="true">arrow_forward</span>

<button type="button" aria-label="Open menu">
  <span class="material-symbols-outlined" aria-hidden="true">menu</span>
</button>

Translations guide

Keep translations, metadata, and language switching on one path.

Files

src/i18n/<code>.ts
src/i18n/index.ts

src/app/feature/language/language.type.ts
src/app/feature/language/language.interface.ts
src/app/feature/language/language.const.ts
src/app/feature/language/language.service.ts

src/app/app.config.ts

`provideTranslate(...)` registers the default language from `src/i18n/index.ts`.

`LanguageService` switches languages with `TranslateService.setMany(...)`.

English source text is used as the translation key.

Store language labels and translations as real UTF-8 text.

When adding or updating translations

  • Add or update the matching `src/i18n/<code>.ts` dictionary.
  • Keep `src/i18n/index.ts` in sync with available language files.
  • Keep language codes aligned with `LanguageCode`.
  • Update `LANGUAGES` when adding or renaming a supported language.
  • Keep English source text identical across templates, components, and dictionaries.
  • Remove unused translation keys when nothing references them anymore.
<span translate>Open language menu</span>
<button [aria-label]="'Go to homepage' | translate" type="button"></button>

private readonly _translateService = inject(TranslateService);

protected readonly toggleLabel = computed(() =>
  this._translateService.translate('Switch to dark mode')(),
);

Environments

Use `src/environments/environment.ts` and `src/environments/environment.prod.ts` for public front-end configuration such as API URLs, feature flags, analytics toggles, and external service settings.

Production builds replace `environment.ts` with `environment.prod.ts`. Do not store secrets in environment files.

Code style

  • Formatting is handled by `.editorconfig` and `.prettierrc`.
  • Tabs
  • Single quotes
  • 100 character line width

AI and requirements

If AI outside the IDE does not automatically read repo rules, include `AGENTS.md` in the prompt or context.

Node.js 20+
npm 11+

Code structure guide

Pages, features, and shared app code each have a home.

Pages

Create app pages inside `src/app/pages/` and lazy load them from `src/app/app.routes.ts`.

src/app/pages/home/home.component.ts
src/app/pages/about/about.component.ts

ng generate component pages/home
ng g c pages/home

Feature modules

For back-end connected business logic, use `src/app/feature/<name>/`.

src/app/feature/user/components/
src/app/feature/user/directives/
src/app/feature/user/interfaces/
src/app/feature/user/pages/
src/app/feature/user/pipes/
src/app/feature/user/services/user.service.ts

ng g c feature/user/pages/user-profile
ng g c feature/user/components/user-card
ng g d feature/user/directives/user-focus
ng g p feature/user/pipes/user-name
ng g s feature/user/services/user

Shared generic code

Reusable code that is not feature-specific can live directly under `src/app`.

src/app/components/
src/app/directives/
src/app/interfaces/
src/app/pipes/phone.pipe.ts
src/app/services/

ng g c components/page-header
ng g d directives/autofocus
ng g p pipes/phone
ng g s services/api

import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    loadComponent: () => import('./pages/home/home.component').then((m) => m.HomeComponent),
  },
  {
    path: 'about',
    loadComponent: () => import('./pages/about/about.component').then((m) => m.AboutComponent),
  },
];

Extra structure notes

  • Interfaces are usually created manually in both `feature` and shared areas.
  • Small colocated features such as `feature/language/language.type.ts` are valid when simpler.
  • Default locations: `src/app/pages`, `src/app/feature/<name>`, and shared `components`, `directives`, `pipes`, `services`, `interfaces`.

src/app/feature/user/interfaces/user.interface.ts
src/app/feature/user/interfaces/user-response.interface.ts
src/app/interfaces/api-response.interface.ts
src/app/interfaces/select-option.interface.ts

Start a new project

Clone the template, install, and run.

git clone https://github.com/IT-Kamianets/ngx-default.git PROJECT_NAME
cd PROJECT_NAME
npm i
npm run start
  • `git clone ... PROJECT_NAME` downloads the template into a new local folder.
  • `cd PROJECT_NAME` moves into that project folder.
  • `npm i` installs dependencies from `package.json`.
  • `npm run start` launches the local development server.
  • After that, open the terminal URL, usually `http://localhost:4200`.

New git history

Reinitialize the repository if you do not want the template history.

rm -rf .git
git init
git remote add origin https://github.com/IT-Kamianets/PROJECT_NAME.git
git add .
git commit -m "chore(init): bootstrap project from ngx-default template"

`git remote add origin ...` connects your local repository to the GitHub remote, and a Conventional Commit like `chore(init): bootstrap project from ngx-default template` is the recommended first commit.

Deployment

Keep the hosting simple and the output predictable.

GitHub Actions can build, copy `CNAME`, and publish the prerendered browser output. The SSR server remains optional infrastructure, not a default runtime dependency.

  1. Install dependencies
  2. Build Angular app
  3. Copy `CNAME`
  4. Push build output to `gh-pages`

Suggested path

`.github/workflows/deploy.yml`

`dist/app/browser`

`dist/app/server`

`CNAME` for the custom domain

`ngx.itkamianets.com` as the example domain

License

MIT

Scripts

npm start
npm run build
npm run serve:ssr:app