An Angular UI component library for TrueNAS and related software. Includes reusable components, comprehensive theming, and automatic icon sprite generation.
# Install latest version
npm install @truenas/ui-components
# Or with yarn
yarn add @truenas/ui-components
# Install specific version
npm install @truenas/[email protected]git clone [email protected]:iXsystems/truenas-ui-components.git
cd truenas-ui-components
yarn installImport components in your Angular application:
import { TnButtonComponent, TnInputComponent } from '@truenas/ui-components';
@Component({
selector: 'app-example',
standalone: true,
imports: [TnButtonComponent, TnInputComponent],
template: `
<tn-button variant="primary">Click me</tn-button>
<tn-input label="Username" placeholder="Enter username"></tn-input>
`
})
export class ExampleComponent {}Add the theme CSS to your angular.json:
{
"styles": [
"node_modules/@truenas/ui-components/src/styles/themes.css",
"src/styles.css"
]
}Apply a theme by adding the theme class to your document root:
document.documentElement.classList.add('tn-dark');Available themes: tn-dark, tn-blue, dracula, nord, paper, solarized-dark, midnight, high-contrast
- Node.js >= 18.19.1
- Yarn >= 4.10.3 (Yarn Berry)
- Angular 20
yarn run sb # Start Storybook (localhost:6006)
yarn build # Build the library
yarn test # Run Jest tests
yarn test-coverage # Run tests with coverage
yarn icons # Generate icon sprite# Build the library
ng build truenas-ui
# Create distributable package
cd dist/truenas-ui && npm packThe build output is located in dist/truenas-ui/ and includes compiled modules, TypeScript declarations, styles, and assets.
The library includes an automatic sprite generation system. Mark icons in your code and they'll be automatically included in the sprite:
import { tnIconMarker } from '@truenas/ui-components';
// MDI icons
tnIconMarker('folder', 'mdi');
// Material icons
tnIconMarker('home', 'material');
// Custom icons
tnIconMarker('dataset', 'custom');Use icons in templates:
<tn-icon name="folder" library="mdi"></tn-icon>
<tn-icon name="dataset" library="custom"></tn-icon>Generate the sprite in your application:
yarn iconsView component documentation and examples:
yarn run sbStorybook provides:
- Interactive component playground
- Complete design system documentation
- Accessibility testing (via @storybook/addon-a11y)
- Code examples and usage guidelines
yarn test # Run all Jest tests
yarn test-cc # Clear cache and run tests
yarn test-coverage # Generate coverage report
yarn test-sb # Run Storybook interaction testsWhen testing components that use TnIconComponent, use TnIconTesting.jest.providers() to avoid manual mocking:
import { TnIconTesting } from '@truenas/ui-components';
await TestBed.configureTestingModule({
imports: [YourComponent],
providers: [
TnIconTesting.jest.providers()
]
}).compileComponents();This replaces the need for manual mocking like:
// ❌ Don't do this anymore
mockProvider(TnSpriteLoaderService, {
ensureSpriteLoaded: jest.fn(() => Promise.resolve(true)),
getIconUrl: jest.fn(),
// ... more boilerplate
}),For advanced testing scenarios, you can customize the mocks by passing overrides:
import { TnIconTesting } from '@truenas/ui-components';
await TestBed.configureTestingModule({
imports: [YourComponent],
providers: [
TnIconTesting.jest.providers({
spriteLoader: {
getIconUrl: jest.fn(() => '#custom-icon')
},
iconRegistry: {
resolveIcon: jest.fn(() => ({
source: 'sprite',
spriteUrl: '#my-icon'
}))
}
})
]
}).compileComponents();Benefits:
- Creates fresh mock instances on each call (no test pollution)
- Icons render as SVG (no fallback text interfering with assertions)
- Simple API for the common case, flexible for advanced needs
Note: The API is designed to support other testing frameworks in the future (e.g., TnIconTesting.vitest.providers()).
See CONTRIBUTE.md for detailed development guidelines, including:
- Icon system documentation
- Component development workflow
- Testing best practices
- Code style conventions
This library requires Angular 20:
{
"@angular/animations": "^20.0.0",
"@angular/cdk": "^20.0.0",
"@angular/common": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
"@angular/platform-browser-dynamic": "^20.0.0",
"@angular/router": "^20.0.0",
"rxjs": "^7.5.0",
"zone.js": "^0.15.0"
}The library is published to npm:
- Releases are automated — merging a PR to
mainwith library code changes triggers a new npm publish - Version bumps are determined by conventional commit types in PR titles (e.g.,
feat:,fix:) - GitHub Releases with release notes are created automatically via Semantic Release
- Consumers install via
npm install @truenas/ui-components - See CONTRIBUTE.md for the full commit message guide
TBD