Modern Angular 21 starter template for building fast landing pages with SSR prerendering, TailwindCSS, and GitHub Pages deployment.
This template is optimized for static landing sites where pages are rendered at build time for SEO and performance.
- Angular 21
- SSR prerendering during build
- Zoneless Angular
- State used in HTML class bindings should be exposed as signals
- Prefer Angular Signal Forms as the primary forms approach when building new forms
- OnPush change detection by default
- TailwindCSS v4
- Use shared theme CSS variables from
src/styles/_theme.scssfor colors, surfaces, spacing, radius, and motion - GitHub Pages deployment
- Prettier formatting
- Clean minimal project structure
The project builds both:
dist/app/browser
dist/app/server
But deployment uses the browser prerendered output, making it perfect for static hosting.
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
app.routes.server.ts
Start the development server:
npm start
or
ng serve
Application runs at http://localhost:4200
Development mode runs as a normal Angular SPA.
Build the project:
npm run build
This generates:
dist/app/browser
dist/app/server
Pages are prerendered at build time using Angular SSR.
The template includes a Node server for SSR:
npm run serve:ssr:app
This runs:
node dist/app/server/server.mjs
For most landing pages this is not required, because prerendered HTML is already generated.
All routes are prerendered by default:
src/app/app.routes.server.ts
RenderMode.Prerender
export const serverRoutes: ServerRoute[] = [
{
path: '**',
renderMode: RenderMode.Prerender,
},
];This makes Angular generate static HTML for every route during build.
The app includes a small bootstrap data flow for company and item data.
Main files:
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
How it works:
APP_INITIALIZERrunsBootstrapService.initialize()during app startup- on the server, bootstrap data is fetched from
${environment.apiUrl}/api/regionit/bootstrap/${environment.companyId} - fetched data is stored in Angular
TransferState - on the browser, transferred data is applied immediately and then refreshed in the background
- if no remote data is available, the app falls back to
environment.companyandenvironment.items
Bootstrap payload shape:
export interface BootstrapData {
company?: Company;
items?: Item[];
}Environment keys involved:
apiUrl- API host used for bootstrap and status checkscompanyId- company identifier sent to the bootstrap endpointcompany- fallback company data used before or instead of API dataitems- fallback item list used before or instead of API dataonApiFall- controls what happens when the API is unavailable
Current fallback behavior in code:
'app'keeps rendering the app with local environment data'app reload'keeps polling${environment.apiUrl}/statusand reloads when the API becomes available
This keeps SSR and prerender safe while still allowing the app to hydrate with API data when it exists.
Tailwind is configured via:
.postcssrc.json
Tailwind should be used as much as possible for everyday UI work.
Prefer Tailwind utilities for:
- layout
- spacing
- typography
- colors
- borders
- sizing
- responsive behavior
Use SCSS only when Tailwind is not the right tool, for example:
- component-specific complex styling
- shared design tokens and mixins
- advanced states or selectors
- small amounts of global styling
Global styles live in:
src/styles.scss
This template includes Material Symbols Outlined and those should be used as the default icon set across the project.
Loaded in:
src/index.html
Use icons directly in HTML like this:
<span class="material-symbols-outlined" aria-hidden="true">arrow_forward</span>For accessible buttons, keep the icon decorative and provide a text label or aria-label on the button itself:
<button type="button" aria-label="Open menu">
<span class="material-symbols-outlined" aria-hidden="true">menu</span>
</button>UI translations live in:
src/i18n/<code>.ts
src/i18n/index.ts
Language metadata lives in:
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
Translation bootstrap starts in:
src/app/app.config.ts
The app uses the wacom translation stack:
provideTranslate(...)registers the default language fromsrc/i18n/index.tsLanguageServiceswitches languages withTranslateService.setMany(...)- English source text is used as the translation key
When adding or updating translations:
- add or update the matching
src/i18n/<code>.tsdictionary - keep
src/i18n/index.tsin sync with the available language files - keep language codes aligned with
LanguageCode - update
LANGUAGESwhen adding or renaming a supported language - keep English source text identical across templates, components, and
src/i18n/* - store translation text and language labels as real UTF-8 characters, not escaped or re-encoded mojibake
- remove unused translation keys when they are no longer referenced anywhere in the app
Supported usage patterns:
- Use the
translatedirective for plain element text content - Use the
translatepipe for interpolations and attribute bindings - Use
TranslateService.translate('Key')()in TypeScript when the translated value is needed insidecomputed()or composed strings
Examples:
<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')(),
);Use SCSS in a way that matches modern Angular defaults:
- Keep most styles inside the component
.scssfile. - Use
src/styles.scssonly for truly global styles like resets, tokens, typography, and utility layers. - Prefer CSS variables for colors, spacing, and theming that may change at runtime.
- Use SCSS features like
@use, mixins, and partials for authoring convenience and shared design tokens. - Avoid deep selector nesting. Keep selectors simple and local to the component.
- Avoid
::ng-deepandViewEncapsulation.Noneunless there is a clear integration reason. - Prefer class bindings in templates over heavy inline style bindings.
Recommended split:
src/styles.scss -> global entry point
src/app/**/**/*.scss -> component-local styles
src/styles/_theme.scss -> shared theme CSS variables
This template includes Angular environment files and they can be used for different runtime setups such as local development and production builds.
Available files:
src/environments/environment.ts
src/environments/environment.prod.ts
Typical use cases:
- API base URLs
- feature flags
- analytics toggles
- external service configuration
Production builds replace environment.ts with environment.prod.ts through Angular file replacements.
Keep environment files limited to public front-end configuration. Do not store secrets in them.
Deployment is handled automatically via GitHub Actions.
Workflow:
.github/workflows/deploy.yml
Steps:
- Install dependencies
- Build Angular app
- Copy
CNAME - Push build output to
gh-pages
The deployed folder is:
dist/app/browser
Custom domain which you should adjust to your own domain so it works properly, any subdomain of *.itkamianets.com in case it's not used before on our github org.
ngx.itkamianets.com
Configured via:
CNAME
Formatting is handled by:
.editorconfig.prettierrc
Key conventions:
- tabs
- single quotes
- 100 character line width
If you use AI outside the IDE and it does not automatically read repository instructions, copy the
contents of AGENTS.md into the AI prompt/context first.
This ensures the AI follows the same project-specific rules that Codex uses inside the IDE.
Start development:
npm start
Build project:
npm run build
Run SSR server:
npm run serve:ssr:app
Recommended environment:
Node.js 20+
npm 11+
Application pages should be created inside:
src/app/pages/
Each page should have its own folder and its own component file.
Example:
src/app/pages/home/home.component.ts
src/app/pages/about/about.component.ts
Generate a page component with Angular CLI:
ng generate component pages/homeor shorter:
ng g c pages/homePages should be lazy loaded from src/app/app.routes.ts.
Example route config:
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),
},
];If a part of the app needs its own business logic and back-end integration, create a dedicated feature folder inside:
src/app/feature/
Each feature should keep its own internal structure.
Example:
src/app/feature/user/
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/
Example service location:
src/app/feature/user/services/user.service.ts
Suggested CLI commands:
Create feature page:
ng g c feature/user/pages/user-profileCreate feature component:
ng g c feature/user/components/user-cardCreate feature directive:
ng g d feature/user/directives/user-focusCreate feature pipe:
ng g p feature/user/pipes/user-nameCreate feature service:
ng g s feature/user/services/userInterfaces are usually created manually:
src/app/feature/user/interfaces/user.interface.ts
src/app/feature/user/interfaces/user-response.interface.ts
For small focused features, colocated files like feature/language/language.type.ts,
language.interface.ts, language.const.ts, and language.service.ts are also valid when that
structure keeps the feature simpler.
Generic reusable code that is not tied to one specific feature can live directly under src/app.
Example shared folders:
src/app/components/
src/app/directives/
src/app/interfaces/
src/app/pipes/
src/app/services/
Example shared pipe location:
src/app/pipes/phone.pipe.ts
Suggested CLI commands:
Create shared component:
ng g c components/page-headerCreate shared directive:
ng g d directives/autofocusCreate shared pipe:
ng g p pipes/phoneCreate shared service:
ng g s services/apiInterfaces are usually created manually:
src/app/interfaces/api-response.interface.ts
src/app/interfaces/select-option.interface.ts
Use these locations by default:
src/app/pages- app-level lazy loaded pagessrc/app/feature/<name>- feature-specific code with back-end/business logicsrc/app/components,directives,pipes,services,interfaces- generic shared code
Clone the default repository into a new folder with your project name (replace PROJECT_NAME with your project name):
git clone https://github.com/IT-Kamianets/ngx-default.git PROJECT_NAME
cd PROJECT_NAME
npm i
npm run startgit clone https://github.com/IT-Kamianets/ngx-default.git PROJECT_NAMEDownloads the template repository and creates a local folder namedPROJECT_NAME.cd PROJECT_NAMEOpens the newly created project folder.npm iInstalls all project dependencies frompackage.json.npm run startStarts the local development server.
After that, open the local URL shown in the terminal, usually http://localhost:4200
If you want to start fresh instead of keeping the template git history, remove the existing .git folder, initialize a new repository, and create the first commit.
Example:
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 remote GitHub repository so future git push and git pull commands know where your main project lives.
Use a Conventional Commit message for the first commit as well. A good default is:
chore(init): bootstrap project from ngx-default template
MIT