Performance Review Matrix
blockhr360-degree employee performance review scorecard and competency matrix: executive metrics, self vs manager rating comparison, detailed competency accordion with manager remarks, OKR progress table, and peer feedback quotes.
Installation
$pnpm dlx uipkge-ng@latest add performance-review-matrix$npx uipkge-ng@latest add performance-review-matrix$yarn dlx uipkge-ng@latest add performance-review-matrix$bunx uipkge-ng@latest add performance-review-matrixManifest:
https://uipkge.dev/r/angular/performance-review-matrix.jsonInstalls to:src/app/components/blocks/performance-review-matrix/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
MetricTileinterface MetricTile {
title: string
value: string
subtitle: string
progress: number
icon: unknown
}AssessmentPillarinterface AssessmentPillar {
title: string
selfScore: number
managerScore: number
delta: string
status: 'consensus' | 'above'
}CompetencyCategoryinterface CompetencyCategory {
id: string
title: string
score: string
ratingLabel: string
badgeVariant: 'success' | 'default' | 'secondary'
progress: number
criteria: string
managerRemarks: string
strengths: string[]
}OKRIteminterface OKRItem {
id: string
title: string
description: string
target: string
progress: number
status: 'Completed' | 'Exceeded' | 'On Track'
statusVariant: 'success' | 'default' | 'secondary'
}PeerFeedbackinterface PeerFeedback {
id: string
quote: string
author: string
role: string
category: string
}Files installed (2)
src/app/components/blocks/performance-review-matrix/performance-review-matrix.component.ts22.1 kB
import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { Award, Calendar, CheckCircle2, FileDown, LucideAngularModule, MessageSquareQuote, Target, TrendingUp, Users, Zap, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiAccordionComponent, UiAccordionContentComponent, UiAccordionItemComponent, UiAccordionTriggerComponent, } from '@/ui/accordion/accordion.component' import { UiAvatarComponent, UiAvatarFallbackComponent, UiAvatarImageComponent } from '@/ui/avatar/avatar.component' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, } from '@/ui/card/card.component' import { UiProgressComponent } from '@/ui/progress/progress.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' import { UiTableBodyComponent, UiTableCellComponent, UiTableComponent, UiTableHeadComponent, UiTableHeaderComponent, UiTableRowComponent, } from '@/ui/table/table.component' interface MetricTile { title: string value: string subtitle: string progress: number icon: unknown } interface AssessmentPillar { title: string selfScore: number managerScore: number delta: string status: 'consensus' | 'above' } interface CompetencyCategory { id: string title: string score: string ratingLabel: string badgeVariant: 'success' | 'default' | 'secondary' progress: number criteria: string managerRemarks: string strengths: string[] } interface OKRItem { id: string title: string description: string target: string progress: number status: 'Completed' | 'Exceeded' | 'On Track' statusVariant: 'success' | 'default' | 'secondary' } interface PeerFeedback { id: string quote: string author: string role: string category: string } const metricTiles: MetricTile[] = [ { title: 'Core Goals Achieved', value: '94%', subtitle: '+4% vs H1 target', progress: 94, icon: Target }, { title: 'Technical Leadership', value: '4.8 / 5.0', subtitle: 'Top 5% org percentile', progress: 96, icon: Award }, { title: 'Culture & Mentorship', value: '4.7 / 5.0', subtitle: '3 mentees promoted', progress: 94, icon: Users }, { title: 'Execution Velocity', value: '4.5 / 5.0', subtitle: '18 epics delivered', progress: 90, icon: Zap }, ] const assessmentPillars: AssessmentPillar[] = [ { title: 'Technical Excellence & Architecture', selfScore: 4.8, managerScore: 5.0, delta: '+0.2 Manager higher', status: 'above', }, { title: 'Collaboration & Mentorship', selfScore: 4.5, managerScore: 4.5, delta: '0.0 Full consensus', status: 'consensus', }, { title: 'Strategic Impact & Roadmapping', selfScore: 4.2, managerScore: 4.5, delta: '+0.3 Manager higher', status: 'above', }, { title: 'Execution Velocity & Delivery', selfScore: 4.5, managerScore: 4.5, delta: '0.0 Full consensus', status: 'consensus', }, ] const competencyCategories: CompetencyCategory[] = [ { id: 'tech-excellence', title: 'Technical Excellence & Architecture', score: '5.0 / 5.0', ratingLabel: 'Outstanding (5.0 / 5.0)', badgeVariant: 'success', progress: 100, criteria: 'Architects resilient, distributed frontend systems. Sets technical standard across multiple squads and prevents architectural debt.', managerRemarks: 'Led the migration to micro-frontends with 0 downtime. Spearheaded the core component architecture and established strict bundle size budgets across the team, lowering bundle footprint by 38%.', strengths: [ 'Zero-downtime micro-frontend rollout', 'Distributed caching architecture', 'Framework token standardization', ], }, { id: 'collab-mentorship', title: 'Collaboration & Mentorship', score: '4.5 / 5.0', ratingLabel: 'Exceeds (4.5 / 5.0)', badgeVariant: 'default', progress: 90, criteria: 'Actively grows engineering talent, fosters inclusive code review practices, and unblocks cross-discipline initiatives.', managerRemarks: 'Mentored 3 junior engineers to promotion. Fostered an open engineering culture, instituted weekly architecture reviews, and unblocked cross-functional teams across APAC and EMEA.', strengths: ['Promotion sponsorship (3 engineers)', 'Weekly architecture reviews', 'Cross-squad pairing cohorts'], }, { id: 'strategic-impact', title: 'Strategic Impact & Roadmapping', score: '4.5 / 5.0', ratingLabel: 'Exceeds (4.5 / 5.0)', badgeVariant: 'default', progress: 90, criteria: 'Aligns engineering strategy with quarterly business goals. Identifies high-ROI technical initiatives and champions developer productivity.', managerRemarks: 'Key driver of developer experience KPIs. Aligned product roadmaps with technical debt reduction, reducing build times by 42% across CI and accelerating shipping velocity.', strengths: ['Developer experience KPIs', 'CI turnaround optimization (-42%)', 'Quarterly tech debt roadmap'], }, ] const okrItems: OKRItem[] = [ { id: 'okr-1', title: 'Micro-Frontend Migration Phase II', description: 'Decompose legacy monolithic checkout and account dashboards into standalone remote modules', target: '100% modules · 0 downtime', progress: 100, status: 'Completed', statusVariant: 'success', }, { id: 'okr-2', title: 'CI Pipeline & Build Acceleration', description: 'Optimize build caching, monorepo graph execution, and parallelize end-to-end test suites', target: '< 4.0m build time (Achieved 3.2m)', progress: 100, status: 'Exceeded', statusVariant: 'success', }, { id: 'okr-3', title: 'Design System Token Federation', description: 'Automate Tailwind OKLCH token sync between Figma variables and registry codebases', target: 'Full Vue & React parity', progress: 85, status: 'On Track', statusVariant: 'default', }, { id: 'okr-4', title: 'Staff Mentorship & Tech Talks', description: 'Host bi-weekly deep dives on web performance, distributed state, and accessibility standards', target: '12 sessions · 3 mentees', progress: 100, status: 'Completed', statusVariant: 'secondary', }, ] const peerFeedbacks: PeerFeedback[] = [ { id: 'peer-1', quote: 'Elena’s architectural guidance transformed our release velocity. Her deep dive sessions on performance optimization helped the frontend team cut latency in half.', author: 'Anonymous Peer', role: 'Staff Frontend Engineer · Checkout Core', category: 'Peer Review · Systems', }, { id: 'peer-2', quote: 'Mentoring from Elena was the highlight of my year. Her patient code reviews and architecture walkthroughs gave me the confidence to lead our squad’s largest migration.', author: 'Direct Mentee', role: 'Software Engineer II · Design Systems', category: 'Mentee Review · Growth', }, { id: 'peer-3', quote: 'Elena bridges technical complexity with product goals effortlessly. She spots risks weeks in advance and consistently delivers robust, high-impact platform features ahead of schedule.', author: 'Cross-Functional Partner', role: 'Principal Product Manager · Core Platform', category: 'Partner Review · Strategy', }, ] /** * PerformanceReviewMatrix -- the React block, 1:1: employee header with overall rating, * executive scorecard tiles, self-vs-manager calibration pillars, a competency accordion * with manager remarks, an OKR progress table, and 360 peer feedback quotes. */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-performance-review-matrix, [ui-performance-review-matrix]', standalone: true, // React renders the root <div> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [ LucideAngularModule, UiAccordionComponent, UiAccordionContentComponent, UiAccordionItemComponent, UiAccordionTriggerComponent, UiAvatarComponent, UiAvatarFallbackComponent, UiAvatarImageComponent, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, UiProgressComponent, UiSeparatorComponent, UiTableComponent, UiTableBodyComponent, UiTableCellComponent, UiTableHeadComponent, UiTableHeaderComponent, UiTableRowComponent, ], template: ` <div data-slot="performance-review-matrix" [class]="rootClass"> <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-content class="p-6"> <div class="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between"> <div class="flex flex-col gap-4 sm:flex-row sm:items-center"> <ui-avatar class="border-border size-16 shrink-0 border sm:size-20"> <ui-avatar-image src="https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200&auto=format&fit=crop&q=80" alt="Elena Rostova" /> <ui-avatar-fallback>ER</ui-avatar-fallback> </ui-avatar> <div class="space-y-1.5"> <div class="flex flex-wrap items-center gap-2"> <h2 class="text-foreground text-xl font-bold tracking-tight sm:text-2xl">Elena Rostova</h2> <span ui-badge variant="secondary" class="font-medium">Senior Staff Engineer</span> </div> <p class="text-muted-foreground text-sm">Core Platform & Architecture · Engineering</p> <div class="flex flex-wrap items-center gap-3 pt-1"> <span ui-badge variant="outline" class="gap-1.5 text-xs font-normal"> <lucide-icon [img]="Calendar" class="size-3.5" /> H2 2026 Review Cycle </span> <ui-separator orientation="vertical" class="hidden h-3.5 sm:block" /> <span class="text-muted-foreground text-xs"> Reviewer: <strong class="text-foreground font-medium">Manager: Marcus Vance</strong> </span> </div> </div> </div> <div class="flex flex-wrap items-center gap-3 sm:self-start lg:self-center"> <span ui-badge variant="success" class="gap-1.5 px-3.5 py-1.5 text-sm font-semibold shadow-xs"> <lucide-icon [img]="Award" class="size-4 shrink-0" /> Exceeds Expectations · 4.6 / 5.0 </span> <button ui-button variant="outline" size="sm" class="gap-2 shadow-xs"> <lucide-icon [img]="FileDown" class="size-4" /> Export PDF Report </button> </div> </div> </div> </div> <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"> @for (tile of metricTiles; track tile.title) { <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-header class="flex flex-row items-center justify-between space-y-0 pb-2"> <h3 ui-card-title class="text-muted-foreground text-xs font-medium">{{ tile.title }}</h3> <lucide-icon [img]="asIcon(tile.icon)" class="text-muted-foreground size-4" /> </div> <div ui-card-content class="space-y-2"> <div class="text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl"> {{ tile.value }} </div> <div class="space-y-1.5"> <ui-progress [value]="tile.progress" class="h-1.5 w-full" /> <div class="flex items-center gap-1"> <lucide-icon [img]="TrendingUp" class="text-success size-3" /> <p class="text-muted-foreground text-xs">{{ tile.subtitle }}</p> </div> </div> </div> </div> } </div> <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-header class="flex flex-col gap-2 pb-4 sm:flex-row sm:items-center sm:justify-between"> <div> <h3 ui-card-title class="text-base font-semibold">Self-Assessment vs Manager Assessment</h3> <p ui-card-description class="text-xs">Consensus and score calibration across core performance pillars.</p> </div> <span ui-badge variant="outline" class="gap-1.5 text-xs font-normal"> <lucide-icon [img]="CheckCircle2" class="text-success size-3.5" /> 96% Consensus Index </span> </div> <div ui-card-content class="space-y-4"> <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"> @for (pillar of assessmentPillars; track pillar.title) { <div class="bg-muted/40 border-border space-y-2.5 rounded-lg border p-3.5"> <div class="flex items-start justify-between gap-2"> <span class="text-foreground line-clamp-1 text-xs font-medium">{{ pillar.title }}</span> <span ui-badge [variant]="pillar.status === 'consensus' ? 'secondary' : 'success'" class="px-1.5 py-0 text-xs font-normal" > {{ pillar.delta }} </span> </div> <div class="space-y-1.5"> <div class="flex items-center justify-between text-xs"> <span class="text-muted-foreground">Self:</span> <span class="text-foreground font-semibold tabular-nums">{{ pillar.selfScore }} / 5.0</span> </div> <ui-progress [value]="(pillar.selfScore / 5) * 100" class="h-1.5 w-full" /> </div> <div class="space-y-1.5"> <div class="flex items-center justify-between text-xs"> <span class="text-muted-foreground">Manager:</span> <span class="text-foreground font-semibold tabular-nums">{{ pillar.managerScore }} / 5.0</span> </div> <ui-progress [value]="(pillar.managerScore / 5) * 100" class="h-1.5 w-full" /> </div> </div> } </div> </div> </div> <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-header class="pb-4"> <h3 ui-card-title class="text-base font-semibold">Competency Breakdown</h3> <p ui-card-description class="text-xs"> Detailed behavioral criteria, manager qualitative remarks, and observable strengths. </p> </div> <div ui-card-content> <ui-accordion type="multiple" [defaultValue]="openCompetencies" class="space-y-3"> @for (category of competencyCategories; track category.id) { <ui-accordion-item [value]="category.id" class="border-border bg-card overflow-hidden rounded-lg border"> <button ui-accordion-trigger class="px-5 py-4 hover:no-underline"> <div class="flex w-full flex-wrap items-center justify-between gap-3 pr-2 text-left"> <div class="space-y-0.5"> <span class="text-foreground text-sm font-semibold">{{ category.title }}</span> <p class="text-muted-foreground line-clamp-1 text-xs">{{ category.criteria }}</p> </div> <div class="flex flex-wrap items-center gap-3"> <span class="text-foreground shrink-0 text-xs font-semibold tabular-nums">{{ category.score }}</span> <span ui-badge [variant]="category.badgeVariant" class="text-xs">{{ category.ratingLabel }}</span> </div> </div> </button> <ui-accordion-content class="px-5 pt-0 pb-5"> <div class="border-border/60 space-y-4 border-t pt-4"> <div class="space-y-1.5"> <div class="flex items-center justify-between text-xs"> <span class="text-muted-foreground font-medium">Competency Mastery</span> <span class="text-foreground font-semibold tabular-nums">{{ category.progress }}%</span> </div> <ui-progress [value]="category.progress" class="h-2 w-full" /> </div> <div class="bg-muted/40 border-border/80 space-y-1.5 rounded-md border p-3.5"> <div class="flex items-center gap-1.5"> <lucide-icon [img]="MessageSquareQuote" class="text-primary size-4 shrink-0" /> <span class="text-foreground text-xs font-medium">Manager Remarks</span> </div> <p class="text-muted-foreground text-xs leading-relaxed">{{ category.managerRemarks }}</p> </div> <div class="space-y-2"> <span class="text-muted-foreground text-xs font-medium">Key Demonstrated Strengths</span> <div class="flex flex-wrap gap-1.5"> @for (strength of category.strengths; track strength) { <span ui-badge variant="outline" class="text-xs font-normal">{{ strength }}</span> } </div> </div> </div> </ui-accordion-content> </ui-accordion-item> } </ui-accordion> </div> </div> <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-header class="pb-4"> <h3 ui-card-title class="text-base font-semibold">Goals & Objectives Progress</h3> <p ui-card-description class="text-xs"> Evaluation of quarterly OKRs, measurable deliverables, and milestone completion. </p> </div> <div ui-card-content> <div class="border-border overflow-hidden rounded-lg border"> <div class="overflow-x-auto"> <table ui-table> <thead ui-table-header class="bg-muted/50"> <tr ui-table-row> <th ui-table-head class="text-xs">Objective & Key Result</th> <th ui-table-head class="text-xs">Target Metric</th> <th ui-table-head class="w-44 text-xs">Progress</th> <th ui-table-head class="text-right text-xs">Status</th> </tr> </thead> <tbody ui-table-body> @for (okr of okrItems; track okr.id) { <tr ui-table-row> <td ui-table-cell class="py-3"> <div class="space-y-0.5"> <p class="text-foreground text-sm font-medium">{{ okr.title }}</p> <p class="text-muted-foreground text-xs">{{ okr.description }}</p> </div> </td> <td ui-table-cell class="text-muted-foreground py-3 text-xs tabular-nums">{{ okr.target }}</td> <td ui-table-cell class="py-3"> <div class="flex items-center gap-2"> <ui-progress [value]="okr.progress" class="h-2 w-24" /> <span class="text-muted-foreground text-xs font-medium tabular-nums" >{{ okr.progress }}%</span > </div> </td> <td ui-table-cell class="py-3 text-right"> <span ui-badge [variant]="okr.statusVariant" class="text-xs">{{ okr.status }}</span> </td> </tr> } </tbody> </table> </div> </div> </div> </div> <div ui-card class="border-border bg-card shadow-xs"> <div ui-card-header class="pb-4"> <h3 ui-card-title class="text-base font-semibold">360° Peer Feedback</h3> <p ui-card-description class="text-xs"> Synthesized qualitative reviews from cross-functional peers, mentees, and collaborators. </p> </div> <div ui-card-content> <div class="grid grid-cols-1 gap-4 lg:grid-cols-3"> @for (peer of peerFeedbacks; track peer.id) { <div class="bg-muted/30 border-border flex flex-col justify-between space-y-3 rounded-lg border p-4.5"> <div class="space-y-2"> <span ui-badge variant="outline" class="text-xs font-normal">{{ peer.category }}</span> <p class="text-foreground text-xs leading-relaxed italic">“{{ peer.quote }}”</p> </div> <div class="border-border/60 border-t pt-3"> <p class="text-foreground text-xs font-semibold">{{ peer.author }}</p> <p class="text-muted-foreground text-xs">{{ peer.role }}</p> </div> </div> } </div> </div> </div> </div> `, }) export class UiPerformanceReviewMatrixComponent { protected readonly Award = Award protected readonly Calendar = Calendar protected readonly CheckCircle2 = CheckCircle2 protected readonly FileDown = FileDown protected readonly MessageSquareQuote = MessageSquareQuote protected readonly TrendingUp = TrendingUp @Input('class') className?: string protected readonly metricTiles = metricTiles protected readonly assessmentPillars = assessmentPillars protected readonly competencyCategories = competencyCategories protected readonly okrItems = okrItems protected readonly peerFeedbacks = peerFeedbacks protected readonly openCompetencies = ['tech-excellence', 'collab-mentorship', 'strategic-impact'] get rootClass(): string { return cn('w-full space-y-6', this.className) } asIcon(icon: unknown): never { return icon as never } }src/app/components/blocks/performance-review-matrix/index.ts0.1 kB
export { UiPerformanceReviewMatrixComponent } from './performance-review-matrix.component'
Raw manifest:https://uipkge.dev/r/angular/performance-review-matrix.json