The Modern Script: Building the In and Out Board
1,730 words, 9 minutes read time.
I hear you—less theory, more syntax. To make this a true “coding style” blog post, we need to look at the implementation through the lens of the 2026 toolchain. We are moving away from the “everything-in-one-file” approach and using a service-oriented architecture that plays nicely with the Heft build system and TypeScript 5.8.
Here is the technical deep dive, complete with the modern code patterns required for a high-performance “In and Out” board.
PHASE 2: WRITE THE BLOG POST (PART 1 – REVISED)
Engineering the “In and Out” Toggle: State, Services, and Syntax
In 2026, a “toggle” is no longer just a UI element; it is a gateway to a multi-service data update. To build a truly responsive “In and Out” board, we must ensure that the user’s interaction feels instantaneous, even if the backend SharePoint list takes a few hundred milliseconds to catch up. This requires a “Reliable State” pattern where we update the React UI immediately (Optimistic UI) and then handle the PnPJS transaction in the background. By using Fluent UI 9, we can leverage the Switch component, which is built for this exact high-frequency interaction. The following code demonstrates how to wrap the PnPJS logic into a clean, reusable service class that the Heft compiler can optimize efficiently.
// services/PresenceService.ts import { spfi, SPFx, SPFI } from "@pnp/sp"; import "@pnp/sp/webs"; import "@pnp/sp/lists"; import "@pnp/sp/items"; export class PresenceService { private _sp: SPFI; constructor(context: any) { this._sp = spfi().using(SPFx(context)); } public async toggleOfficeStatus(userId: number, currentStatus: boolean): Promise<void> { const list = this._sp.web.lists.getByTitle("PresenceTracker"); // Efficiently finding the user's record for today const today = new Date().toISOString().split('T')[0]; const items = await list.items .filter(`AuthorId eq ${userId} and Created ge '${today}'`)(); if (items.length > 0) { await list.items.getById(items[0].Id).update({ IsInOffice: !currentStatus, LastCheckIn: new Date().toISOString() }); } else { await list.items.add({ Title: `Status Update - ${today}`, IsInOffice: !currentStatus, LastCheckIn: new Date().toISOString() }); } } } This service layer is the backbone of our application. Note the use of the ge (greater than or equal to) OData filter; this ensures we are only touching records from the current day, preventing the web part from scanning thousands of legacy rows as the year progresses. Furthermore, by using the SPFx(context) injection, we ensure that our calls are scoped correctly within the SharePoint environment without needing to manually manage authentication tokens. This clean separation of concerns makes the code significantly easier to unit test with Jest, which is now the integrated testing standard for Heft-based projects in 2026.
Designing the Dashboard: Aggregating Team Presence with React Hooks
Once the toggle logic is secured, the next challenge is rendering the “Team Board” itself. In 2026, we avoid the “Prop Drilling” of the past by using a combination of custom React Hooks and the Fluent UI 9 Table components. The dashboard needs to pull a list of all employees and cross-reference them with our PresenceTracker list. To keep the UI fluid, we implement a usePresence hook that manages the polling logic—ensuring that if a teammate toggles their status on another floor, the board updates without a page refresh. This is a critical requirement for a modern office where “In” or “Out” status changes by the minute.
// hooks/usePresence.ts import { useState, useEffect } from 'react'; import { PresenceService } from '../services/PresenceService'; export const usePresence = (context: any) => { const [statuses, setStatuses] = useState<any[]>([]); const service = new PresenceService(context); const fetchStatuses = async () => { const data = await service.getAllPresenceRecords(); // Implementation of fetch logic setStatuses(data); }; useEffect(() => { fetchStatuses(); const interval = setInterval(fetchStatuses, 30000); // Poll every 30 seconds return () => clearInterval(interval); }, []); return { statuses, refresh: fetchStatuses }; }; In the main component, we map these statuses to a grid of Fluent UI 9 Avatars. Using the PresenceBadge slot within the Avatar component allows us to visually communicate the “In” status (Green badge) versus “Out” or “Remote” (Empty or Grey badge). This creates a high-density, high-information view that fits perfectly into a SharePoint sidebar or a Microsoft Teams tab. Consequently, the “In and Out” board becomes a central hub for team coordination, built on a foundation of clean, modular TypeScript that adheres to the strictest 2026 development standards.
Synchronizing the Physical and Digital: Microsoft Graph API Integration
While our custom SharePoint list acts as the authoritative source for “In-Office” status, a truly modern 2026 “In and Out Board” must acknowledge the user’s broader digital footprint. In a hybrid environment, an employee might be physically in the office but “In a Meeting” or “Do Not Disturb” on Microsoft Teams. To provide the most accurate picture, we integrate the Microsoft Graph API to overlay real-time Teams presence on top of our manual office toggle. By utilizing the MSGraphClientV3, we can fetch the presence resource for the entire team in a single batch request, which is significantly more efficient than individual calls.
// services/GraphPresenceService.ts import { MSGraphClientV3 } from '@microsoft/sp-http'; export class GraphPresenceService { constructor(private context: any) {} public async getBatchPresence(userIds: string[]): Promise<any> { const client: MSGraphClientV3 = await this.context.msGraphClientFactory.getClient('3'); // Using the 2026 Batch API endpoint for optimized performance const requestBody = { ids: userIds }; const response = await client .api('/communications/getPresencesByUserId') .post(requestBody); return response.value; } } The logic here is to prioritize the physical status from our SharePoint list while using the Graph data to “decorate” the UI. For instance, if our list says a user is “In Office,” we render the green office icon, but we can also add a small sub-indicator—like a red dot—if the Graph API reports they are currently in a call. This dual-layer data strategy ensures that coworkers don’t just know where someone is, but also how reachable they are at that exact moment. From a coding perspective, this involves merging two distinct data arrays (SharePoint items and Graph objects) into a single unified state object before rendering.
Optimizing for 2026 Environments: Performance and Mobile-First Viva Views
As we move toward the final deployment phase, we must optimize the board for the “Unified App” model. In 2026, SPFx web parts are rarely consumed solely on a desktop browser; they are pinned as Teams personal apps and surfaced as Viva Connections cards. To handle these varied environments, we must implement conditional rendering and CSS container queries. Using Fluent UI 9’s makeStyles, we can define a layout that automatically shifts from a multi-column grid on a wide SharePoint page to a single-stack list on a mobile device.
// components/PresenceCard.styles.ts import { makeStyles, tokens } from '@fluentui/react-components'; export const useStyles = makeStyles({ card: { display: 'flex', alignItems: 'center', padding: '12px', borderRadius: tokens.borderRadiusMedium, backgroundColor: tokens.colorNeutralBackground1, boxShadow: tokens.shadow4, transition: 'transform 0.2s ease-in-out', ':hover': { transform: 'scale(1.02)', cursor: 'pointer' } }, statusIndicator: { marginLeft: 'auto', fontWeight: tokens.fontWeightSemibold } }); Furthermore, we utilize Dynamic Imports (React Lazy/Suspense) for the more “expensive” parts of the board, such as the administrative reporting dashboard or the history charts. By splitting the code, we ensure that the main “In/Out” toggle—the primary feature users need on the go—loads in under a second on mobile networks. This performance-first mindset is what separates a standard SharePoint customizer from a professional M365 developer in 2026. Consequently, our “In and Out Board” becomes a lightweight, essential tool that lives wherever the user works, providing consistent value across the entire Microsoft 365 suite.
Deploying for 2026: Automating the Board’s Lifecycle
As we reach the conclusion of our “In and Out Board” development, we must address the final, and perhaps most critical, step: moving the code from a developer’s workstation to the corporate App Catalog. In 2026, the transition to Heft has fundamentally changed our packaging commands, replacing the long-standing Gulp tasks with more efficient, production-optimized orchestrations. To generate the final .sppkg file for our presence tracker, we no longer use gulp bundle --ship; instead, we execute heft build --production followed by heft package-solution --production. This process leverages the latest TypeScript 5.8 optimizations and ensures that the Fluent UI 9 components are correctly tree-shaken, resulting in a lightweight package that respects the tenant’s performance budgets.
Modern deployment in 2026 is rarely a manual process. Enterprise organizations now demand CI/CD (Continuous Integration/Continuous Deployment) pipelines that validate code quality and security before any package reaches production. By using GitHub Actions, we can automate the build of our “In and Out Board” every time a change is merged into the main branch. This pipeline not only compiles the code using the Heft orchestrator but also runs our Jest unit tests and ESLint rules to ensure that the office presence logic remains sound. Once the build is verified, the pipeline utilizes the CLI for Microsoft 365 to securely upload and deploy the package to the SharePoint App Catalog. This level of automation reduces the risk of human error and ensures that the team always has access to the most stable and secure version of their presence tools.
# .github/workflows/deploy-spfx.yml name: SPFx Build & Deploy (2026 Heft Edition) on: push: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Use Node.js v22 uses: actions/setup-node@v4 with: node-version: '22' - name: Install Dependencies run: npm install - name: Heft Build and Package run: | npx heft build --production npx heft package-solution --production - name: Deploy to SharePoint App Catalog uses: pnp/action-cli-login@v2 with: ADMIN_USERNAME: ${{ secrets.M365_USERNAME }} ADMIN_PASSWORD: ${{ secrets.M365_PASSWORD }} - name: Upload and Deploy run: | m365 spo app add --filePath "./sharepoint/solution/in-out-board.sppkg" --overwrite --publish This automated workflow is the final piece of our “In and Out Board” puzzle. It transforms a local coding project into a professional, enterprise-ready utility that supports the hybrid workforce of 2026. By combining the data-rich capabilities of SharePoint and the Microsoft Graph with the high-performance UI of Fluent UI 9, we have built a tool that is more than just a list—it is a central nervous system for team visibility. As the SharePoint Framework continues to evolve with upcoming features like SPFx v1.23 and its promise of open-sourced templates, the principles we’ve applied here—modular services, modern state management, and automated deployment—will remain the gold standard for Microsoft 365 development.
Modern SPFx Build Tooling deep dive
This video provides a practical walkthrough of the significant shift from Gulp to Heft in the latest SPFx releases, which is the foundational change for the deployment logic we’ve implemented in this post.
Call to Action
If this post sparked your creativity, don’t just scroll past. Join the community of makers and tinkerers—people turning ideas into reality with 3D printing. Subscribe for more 3D printing guides and projects, drop a comment sharing what you’re printing, or reach out and tell me about your latest project. Let’s build together.
D. Bryan King
Sources
Disclaimer:
The views and opinions expressed in this post are solely those of the author. The information provided is based on personal research, experience, and understanding of the subject matter at the time of writing. Readers should consult relevant experts or authorities for specific guidance related to their unique situations.
#buildingOfficeUtilities #CICDForSharePoint #clientSideWebParts #collaborativePortals #customSharePointSolutions #enterpriseSPFxDevelopment #FluentUI9 #FluentUI9Tokens #GitHubActionsSPFx #HeftBuildSystem #hybridWorkTools #Microsoft365CLI #Microsoft365Development #Microsoft365Ecosystem #Microsoft365Engineering #Microsoft365UnifiedAppModel #MicrosoftGraphAPIPresence #MicrosoftGraphBatching #modernM365Architecture #MSGraphClientV3Batching #NodeJsV22SharePoint #ODataFiltersPnPJS #OfficePresenceWebPart #OptimisticUIReact #PnPJSV4Tutorial #presenceBadgeImplementation #presenceTrackingLogic #ReactHooksForSharePoint #ReactLazyLoadingSPFx #realTimeDataFetching #SharePointAPIThrottling #SharePointAppCatalogDeployment #SharePointDeveloperBlog #SharePointDevelopmentCodingStyle #SharePointFramework2026 #SharePointFrameworkBestPractices #SharePointInAndOutBoard #SharePointIntranetInnovation #SharePointListIntegration #SharePointTechnicalGhostwriter #SPFxCodingStandards #SPFxCSSContainerQueries #SPFxDeploymentAutomation #SPFxExtensionDevelopment #SPFxPerformanceOptimization #SPFxProjectStructure2026 #SPFxRigConfiguration #SPFxServiceArchitecture #SPFxTutorialWithCode #SPFxUnitTestingJest #SPFxV122 #SPFxV123Roadmap #SPFxWorkspaceSetup #TeamsPersonalTabs #TheModernScriptBlog #treeShakingFluentUI #TypeScript58SPFx #VivaConnectionsCards #webPartStateManagement

