This is an Angular Library.
- Getting Started
- Development server
- Build
- Switching Between Local and Published Versions
- Running unit tests
- Angular code scaffolding
- Commonly Used Commands
- Using This Library
- Publishing the Library
Running the application requires the following tools to be installed in your environment:
Install dependencies by executing the following command:
yarn
Run yarn ng build to build the project. The build artifacts will be stored in the dist/ directory.
See opal-frontend for how this library is consumed in practice.
Use the yarn import:local:common-ui-lib and yarn import:published:common-ui-lib scripts in your consuming project (opal-frontend) to switch between local development and the published npm version of the library.
To use a published version of this library during development in another project:
- In the consuming project, run:
yarn import:published:common-ui-lib
To use a local version of this library during development in another project:
-
Build this library:
yarn build
-
In your consuming project (e.g.
opal-frontend), ensure you have set an environment variable pointing to the local build:# In your shell config file (.zshrc, .bash_profile, or .bashrc) export COMMON_UI_LIB_PATH="[INSERT PATH TO COMMON UI LIB FOLDER]"
-
In the consuming project (e.g.
opal-frontend), run:yarn import:local:common-ui-lib
This will remove the published version and install the local build using the path provided.
-
To switch back to the published version:
yarn import:published:common-ui-lib
This setup makes it easy to switch between development and production versions of the shared library.
Once any changes have been approved and merged into the main branch, you'll need to publish a new version of the library so that it can be consumed by other projects. To do this:
- Increment the version number in both the library's root
package.jsonand in/projects/opal-frontend-common/package.json. - Commit and push those changes to the main branch.
- On GitHub, create a new release and use the updated version number as a tag.
- When the release workflow completes, the library will be published.
After this new version of the library is published, any consuming application should remove the local or outdated version of the library and then install the published version by running:
```bash
yarn import:published:common-ui-lib
```
Run yarn test to execute the unit tests via karma.
To check code coverage, run yarn test:coverage to execute the unit tests via karma but with code coverage.
The coverage report will be available in the coverage/ directory (e.g. coverage/index.html).
This library uses the prefix opal-lib for all of its shared components, as specified in the angular.json file. When generating new components, make sure they are prefixed accordingly. This ensures consistent naming and avoids naming collisions across applications.
Run yarn ng generate component component-name to generate a new component. You can also use yarn ng generate directive|pipe|service|class|guard|interface|enum|module.
Note the requirement for prefixing the ng commands with yarn
This library uses multiple entry points, which allows you to organize and expose different parts of the library in separate modules. Each entry point requires:
- An
ng-package.jsonto define how the entry point should be packaged. - A
package.jsonto specify the entry point's metadata and dependencies. - A
public-api.tsto declare and export the resources for that entry point.
Alias paths need to be set in both the /projects/opal-frontend-common/package.json and the library's tsconfig.json. These aliases help the consuming application import from each entry point using the correct path. By properly defining these aliases, developers can import modules from your library entry points without resorting to complex relative paths.
To import a module from a specific entry point in your application:
// Example: Importing various items from the library
import { GovukTextInputComponent } from '@hmcts/opal-frontend-common/components/govuk/govuk-text-input';
import { DateService } from '@hmcts/opal-frontend-common/services/date-service';
import { dateOfBirthValidator } from '@hmcts/opal-frontend-common/validators/date-of-birth';
import { hasFlowStateGuard } from '@hmcts/opal-frontend-common/guards/has-flow-state';
import { TitleResolver } from '@hmcts/opal-frontend-common/resolvers/title';
import { GlobalStore } from '@hmcts/opal-frontend-common/stores/global';The following commands are available in the package.json:
-
yarn build
Builds the Angular library and outputs to thedist/folder. -
yarn test
Executes unit tests via karma. -
yarn test:coverage
Runs unit tests with code coverage reporting enabled. The coverage report can be found in thecoverage/directory. -
yarn lint
Runs linting using ESLint.There is a custom lint rule for member ordering to ensure members in the code are ordered in the following format:
[
"private-static-field",
"protected-static-field",
"public-static-field",
"private-instance-field",
"protected-instance-field",
"public-instance-field",
"constructor",
"private-static-method",
"protected-static-method",
"public-static-method",
"private-instance-method",
"protected-instance-method",
"public-instance-method"
]-
yarn prettier
Checks that all files conform to the Prettier formatting rules. -
yarn prettier:fix
Automatically formats files using Prettier.
https://angular.dev/ai/develop-with-ai
Paste the following prompt into your AI assistant of choice.
You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.
## TypeScript Best Practices
- Use strict type checking
- Prefer type inference when the type is obvious
- Avoid the `any` type; use `unknown` when type is uncertain
## Angular Best Practices
- Always use standalone components over NgModules
- Do NOT set `standalone: true` inside the `@Component`, `@Directive` and `@Pipe` decorators
- Use signals for state management
- Implement lazy loading for feature routes
- Use `NgOptimizedImage` for all static images.
- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead
## Components
- Keep components small and focused on a single responsibility
- Use `input()` and `output()` functions instead of decorators
- Use `computed()` for derived state
- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator
- Prefer inline templates for small components
- Prefer Reactive forms instead of Template-driven ones
- Do NOT use `ngClass`, use `class` bindings instead
- DO NOT use `ngStyle`, use `style` bindings instead
## State Management
- Use signals for local component state
- Use `computed()` for derived state
- Keep state transformations pure and predictable
- Do NOT use `mutate` on signals, use `update` or `set` instead
## Templates
- Keep templates simple and avoid complex logic
- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`
- Use the async pipe to handle observables
## Services
- Design services around a single responsibility
- Use the `providedIn: 'root'` option for singleton services
- Use the `inject()` function instead of constructor injectionPrompt:
“How do Angular signals work?”
What Copilot does:
Calls search_documentation("signals") and returns official Angular documentation context.
Prompt:
“Generate a service for user authentication”
What Copilot does:
Runs ng generate service user-auth through the MCP server — adds the file in the correct directory.
Prompt:
“List all Angular modules in this project”
What Copilot does:
Uses list_projects and get_file_tree to find and display modules across the workspace.
Prompt:
“What routes are defined in this app?”
What Copilot does:
Parses routing modules and shows route paths, guards, and lazy-loaded modules.
Prompt:
“Convert this component to use the standalone API”
What Copilot does:
Updates component metadata with standalone: true, refactors imports, and removes old NgModule references.
Prompt:
“Add Angular Material”
What Copilot does:
Triggers ng add @angular/material to install the package and configure animations + theming.