Photonix

AllocationMatrixWidget

A specialized widget for visualizing resource allocation across multiple projects and team members.

Preview

Team allocation

Current sprint
Members / Projects
Docs
Design system
Jane Cooper
Designer
60%
40%
Wade Warren
Engineer
85%
Usage
"use client";

import { AllocationMatrixWidget, type MatrixAllocation, type MatrixMember, type MatrixProject } from '@photonix/ultimate';

const projects: MatrixProject[] = [
    { id: 'docs', name: 'Docs' },
    { id: 'system', name: 'Design system' },
];

const members: MatrixMember[] = [
    { id: 'jane', name: 'Jane Cooper', role: 'Designer' },
    { id: 'wade', name: 'Wade Warren', role: 'Engineer' },
];

const allocations: MatrixAllocation[] = [
    { memberId: 'jane', projectId: 'docs', percentage: 60 },
    { memberId: 'jane', projectId: 'system', percentage: 40 },
    { memberId: 'wade', projectId: 'system', percentage: 85 },
];

export default function AllocationMatrixWidgetBasicExample() {
    return (
        <AllocationMatrixWidget
            title="Team allocation"
            subtitle="Current sprint"
            projects={projects}
            members={members}
            allocations={allocations}
            height={320}
        />
    );
}

Component API

AllocationMatrixWidget

Prop
Type
Default
Description
title
string
-
Header title
subtitle
string
-
Header subtitle
projects
MatrixProject[]
[]
Array of project items
members
MatrixMember[]
[]
Array of member items
allocations
MatrixAllocation[]
[]
Array of allocation items
dateRange
AllocationMatrixDateRange
-
Optional date range used to filter or aggregate time-based allocations
loading
boolean
false
Loading state
headerExtraContent
React.ReactNode
-
Component to display in the header (e.g., custom filters)
footer
React.ReactNode
-
Content to display below the matrix
height
string | number
-
Component height
onCellClick
((memberId: string, projectId: string) => void)
-
Click handler for a cell
appearance
WidgetAppearance
'outlined'
Widget appearance
padding
string | number
-
Widget padding (default: 16px)
className
string
-
Custom class name
style
React.CSSProperties
-
Custom style

Variants

With Time Filter

Use dateRange together with allocations that include startDate and endDate to enable native time filtering.

Resource Allocation

Allocation filtered across 1 matching period(s)
Members / Projects
Digital Infrastructure 2026
Brand Identity Reload
Mobile App V2
Sarah Connor
Frontend Lead
40%
60%
John Reese
Backend Engineer
20%
80%
Ellen Ripley
Designer
100%

Selected range: 01/01/2026 - 31/03/2026 • Matching periods: Q1 2026

With Time Filter
"use client";

import { useState } from 'react';
import { AllocationMatrixWidget, Box, DateRangePicker, type DateRange } from '@photonix/ultimate';

const PROJECTS = [
    { id: 'p1', name: 'Digital Infrastructure 2026' },
    { id: 'p2', name: 'Brand Identity Reload' },
    { id: 'p3', name: 'Mobile App V2' },
];

const MEMBERS = [
    { id: 'm1', name: 'Sarah Connor', role: 'Frontend Lead' },
    { id: 'm2', name: 'John Reese', role: 'Backend Engineer' },
    { id: 'm3', name: 'Ellen Ripley', role: 'Designer' },
];

const PERIODS = [
    { label: 'Q1 2026', start: new Date(2026, 0, 1), end: new Date(2026, 2, 31), allocations: [
        { projectId: 'p1', memberId: 'm1', percentage: 40 }, { projectId: 'p2', memberId: 'm1', percentage: 60 }, { projectId: 'p1', memberId: 'm2', percentage: 20 }, { projectId: 'p3', memberId: 'm2', percentage: 80 }, { projectId: 'p2', memberId: 'm3', percentage: 100 },
    ]},
    { label: 'Q2 2026', start: new Date(2026, 3, 1), end: new Date(2026, 5, 30), allocations: [
        { projectId: 'p1', memberId: 'm1', percentage: 25 }, { projectId: 'p3', memberId: 'm1', percentage: 75 }, { projectId: 'p1', memberId: 'm2', percentage: 50 }, { projectId: 'p2', memberId: 'm2', percentage: 25 }, { projectId: 'p3', memberId: 'm2', percentage: 25 }, { projectId: 'p2', memberId: 'm3', percentage: 40 }, { projectId: 'p3', memberId: 'm3', percentage: 60 },
    ]},
];

const TIMED_ALLOCATIONS = PERIODS.flatMap((period) => period.allocations.map((allocation) => ({ ...allocation, startDate: period.start, endDate: period.end })));
const DEFAULT_RANGE = { start: new Date(2026, 0, 1), end: new Date(2026, 2, 31) };

const getEffectiveRange = (range?: DateRange) => {
    const start = range?.start ?? DEFAULT_RANGE.start;
    const end = range?.end ?? range?.start ?? DEFAULT_RANGE.end;
    return start <= end ? { start, end } : { start: end, end: start };
};

export default function AllocationMatrixWidgetFilterExample() {
    const [dateRange, setDateRange] = useState<DateRange | undefined>(DEFAULT_RANGE);
    const effectiveRange = getEffectiveRange(dateRange);
    const matchedPeriods = PERIODS.filter((period) => period.start <= effectiveRange.end && period.end >= effectiveRange.start);
    const matchedPeriodLabel = matchedPeriods.map((period) => period.label).join(', ');

    return (
        <Box w="100%">
            <AllocationMatrixWidget
                title="Resource Allocation"
                subtitle={`Allocation filtered across ${matchedPeriods.length} matching period(s)`}
                projects={PROJECTS}
                members={MEMBERS}
                allocations={TIMED_ALLOCATIONS}
                dateRange={dateRange}
                headerExtraContent={(
                    <DateRangePicker
                        variant="single"
                        value={dateRange}
                        onChange={setDateRange}
                        labelStyle="outside"
                        placeholder="Select range"
                        showPresets
                        fullWidth={false}
                    />
                )}
                footer={
                    matchedPeriods.length > 0
                        ? `Selected range: ${effectiveRange.start.toLocaleDateString('en-GB')} - ${effectiveRange.end.toLocaleDateString('en-GB')} • Matching periods: ${matchedPeriodLabel}`
                        : 'No allocation data overlaps with the selected period.'
                }
            />
        </Box>
    );
}

Loading State

Displays a skeleton preview while data is being fetched.

Loading State
"use client";

import { AllocationMatrixWidget, Box } from '@photonix/ultimate';

export default function AllocationMatrixWidgetLoadingExample() {
    return (
        <Box w="100%">
            <AllocationMatrixWidget title="Allocation" projects={[]} members={[]} allocations={[]} loading height={300} />
        </Box>
    );
}

On this page

Preview
Component API
Variants
With Time Filter
Loading State
With Footer
Photonix UI - React Components, Templates & Figma Design System