Skip to content

Conversation

@JeremyRH
Copy link
Contributor

@JeremyRH JeremyRH commented Jan 8, 2026

This pull request adds a server-safe utility for unique ID generation. It uses an incrementing counter scoped to the module that resets after Number.MAX_SAFE_INTEGER. This prevents an overflow server-side because the counter is server-side state when using SSR.

I tried to remove generated IDs but too many Property tests rely on them.

It does not fix hydration mismatches. I could not find a solution that keeps the IDs the same server and client side using an incrementing counter. Incrementing counter ID is needed for Property tests. It's possible to introduce Context to hold the counter and we can use this new context in apps that SSR.

PR removes all prop-types because it's depreciated and noisy.

@JeremyRH JeremyRH requested a review from Copilot January 8, 2026 17:47
@JeremyRH JeremyRH requested a review from a team as a code owner January 8, 2026 17:47
@kermitapp
Copy link

kermitapp bot commented Jan 8, 2026

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors ID generation to support Server-Side Rendering (SSR) by making all generated IDs client-side only. The main approach is using a new useUniqueClientId hook that generates IDs in useEffect after the initial render, ensuring SSR and client hydration compatibility.

Key changes:

  • Introduced useUniqueClientId hook that defers ID generation to client-side via useEffect
  • Removed unnecessary IDs where accessibility can be maintained without them (using title attributes, wrapping labels, or element refs)
  • Converted several class components to function components (FormChoice, CheckboxBooleanInput, Icon)
  • Consolidated Icon implementation by merging FontAwesomeAPM into Icon component

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/hooks/useUniqueClientId.ts New hook for SSR-compatible client-side ID generation
src/components/TruncatedText/TruncatedText.tsx Replaced ID-based tooltip targeting with refs
src/components/Tree/TreeItem.tsx Removed unnecessary checkbox ID
src/components/Tooltip/TooltipButton.tsx Migrated to useUniqueClientId hook, removed aria-describedby
src/components/Table/SortableTable.js Replaced label+ID pattern with title attributes, moved defaultProps
src/components/Status/Status.tsx Updated import to use IconProps instead of FontAwesomeAPMProps
src/components/List/components/SortHeader.tsx Wrapped label around select input, removed PropTypes
src/components/List/components/FilterHeader.tsx Replaced label+ID with title attribute, removed PropTypes
src/components/List/SortableList.tsx Removed PropTypes, added Item type interface
src/components/List/ListItem.tsx Migrated to useUniqueClientId, replaced label with title
src/components/List/List.tsx Migrated to useUniqueClientId, replaced Row with fragment, removed PropTypes
src/components/List/List.spec.js Updated tests from getByLabelText to getByTitle
src/components/Icon/Icon.tsx Merged FontAwesomeAPM, converted to forwardRef function component
src/components/Icon/FontAwesomeAPM.tsx Deleted, merged into Icon.tsx
src/components/HelpBubble/HelpBubble.tsx Migrated to useUniqueClientId hook
src/components/HasManyFields/HasManyFieldsRow.tsx Replaced ID-based tooltip with ref-based approach
src/components/HasManyFields/HasManyFieldsRow.spec.js Removed tests for disabled tooltip behavior
src/components/Form/FormChoice.tsx Converted from class to function, added useUniqueClientId, fixed cursor style bug
src/components/Form/FormChoice.spec.js Removed ID generation test
src/components/Form/FormChoice.js Deleted, replaced with TypeScript version
src/components/Form/FormChoice.d.ts Deleted, types now in .tsx file
src/components/Checkbox/CheckboxBooleanInput.tsx Converted from class to function, added useUniqueClientId
Comments suppressed due to low confidence (1)

src/components/HasManyFields/HasManyFieldsRow.tsx:27

  • The default props have been moved inline in the function parameters, but the noop function is still defined separately. For consistency, consider either defining all defaults inline (replacing onDelete = noop with an inline function) or removing the now-unused noop constant since it's only used once.
const noop = () => undefined;

interface HasManyFieldsRowProps {
  children: React.ReactNode;
  className?: string;
  onDelete?: React.MouseEventHandler<any>;
  deletable?: boolean;
  deleteProps?: ConfirmationButtonProps;
  disabled?: boolean;
  disabledReason?: React.ReactNode;
  disabledReasonPlacement?: Placement;
}

const HasManyFieldsRow = ({
  children,
  className,
  disabledReason,
  onDelete = noop,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JeremyRH JeremyRH force-pushed the fee-1480-refactor-dynamic-id-generation branch from 6f8b824 to f44bc54 Compare January 8, 2026 18:57
@JeremyRH JeremyRH requested a review from Copilot January 8, 2026 18:57
@JeremyRH JeremyRH changed the title Make generated IDs only client-side to support SSR client-side only IDs, remove PropTypes Jan 8, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 57 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JeremyRH JeremyRH force-pushed the fee-1480-refactor-dynamic-id-generation branch from c7a27d1 to 1d32caf Compare January 9, 2026 20:28
@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

Released prerelease version 8.18.1-fee-1480-refactor-dynamic-id-generation-d548d3a.0.
You may now run npm install @appfolio/react-gears@fee-1480-refactor-dynamic-id-generation

@JeremyRH JeremyRH changed the title client-side only IDs, remove PropTypes SSR safe IDs, remove PropTypes Jan 9, 2026
@JeremyRH JeremyRH merged commit 24f2889 into master Jan 9, 2026
5 checks passed
@JeremyRH JeremyRH deleted the fee-1480-refactor-dynamic-id-generation branch January 9, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants