Skip to content

Uniform modal component#5741

Open
shatfield4 wants to merge 14 commits into
masterfrom
feat/uniform-modal-component
Open

Uniform modal component#5741
shatfield4 wants to merge 14 commits into
masterfrom
feat/uniform-modal-component

Conversation

@shatfield4

@shatfield4 shatfield4 commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Type

  • ✨ feat (New feature)
  • 🐛 fix (Bug fix)
  • ♻️ refactor (Code refactoring without changing behavior)
  • 💄 style (UI style changes)
  • 🔨 chore (Build, CI, maintenance)
  • 📝 docs (Documentation updates)

Relevant Issues

resolves #

Description

  • Adds a single reusable Modal component at frontend/src/components/lib/Modal/index.jsx and migrates all app modals to it so every modal is visually uniform across light and dark mode
  • Normalizes styling away from bg-theme-* CSS variables to explicit zinc (dark) / light:slate (light) color pairs from designs
  • Modal is the entrypoint: render it with isOpen and onClose, and pass whatever JSX you want as children
  • Modal props: isOpen, onClose, size (sm 400px / md 500px / lg 640px / xl 868px, default md), variant (default renders the uniform card, bare just centers raw children for non-card modals like lightboxes), className (extra classes on the backdrop, e.g. a higher z- to clear a fixed top bar), closeOnEsc (default true), and noPortal (render inline instead of portaling to #root)
  • Pressing Esc now closes any modal by calling onClose; opt out per modal with closeOnEsc={false} for flows that require a forced choice
  • Compose the inside with the named exports rather than hand-rolling layout: ModalHeader, ModalBody, ModalFooter
  • ModalHeader takes title, optional subtitle, and onClose (renders the close X when provided)
  • ModalBody is the unopinionated content region with standard field spacing; pass className to override
  • ModalFooter is the action row; it auto right-aligns when there is a single button and uses space-between when there are multiple
  • Button helpers: ModalPrimaryButton (Save/Create), ModalSecondaryButton (Cancel), ModalDangerButton (Delete) — all share the uniform sizing and just take normal button props
  • Field helpers: ModalInput and ModalTextarea render a label, the field, and an optional hint together; both accept label, hint, optional, and forward the rest to the underlying input/textarea
  • Lower-level helpers ModalLabel and ModalHint are available when you need just the label or hint on their own
  • Focus styling is consistent: inputs/textareas recolor their border to sky-500 on focus (no offset outline gap) in both light and dark mode

Visuals (if applicable)

Additional Information

  • I individually tested each modal that we touched with the testing checklist commented below
  • When testing be sure to test every single modal that was modified since many styles were changed/normalized

Developer Validations

  • I ran yarn lint from the root of the repo & committed changes
  • Relevant documentation has been updated (if applicable)
  • I have tested my code functionality
  • Docker build succeeds locally

@shatfield4 shatfield4 self-assigned this Jun 2, 2026
@shatfield4

shatfield4 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Modal testing checklist:

  • components/lib/Modal/index.jsx — the component + all exports
  • components/Modals/DisplayRecoveryCodeModal/index.jsx
  • components/Modals/ManageWorkspace/index.jsx — mobile card migrated; desktop shell colors normalized
  • components/Modals/ManageWorkspace/Documents/Directory/NewFolderModal/index.jsx — reference example
  • components/Modals/ManageWorkspace/Documents/WorkspaceDirectory/index.jsx — PinAlert + DocumentWatchAlert
  • components/Modals/NewWorkspace.jsx
  • components/Modals/Password/MultiUserAuth.jsx — recovery-code child only; forced-choice preserved
  • components/Modals/Password/SingleUserAuth.jsx — same
  • components/UserMenu/AccountModal/index.jsx — heavy form (pfp, fields, prefs)
  • components/KeyboardShortcutsHelp/index.jsx — shortcuts grid
  • components/WorkspaceChat/index.jsx — "Workspace not found" forced-choice modal
  • components/WorkspaceChat/ChatContainer/ChatHistory/Citation/index.jsx — CitationDetailModal
  • components/WorkspaceChat/ChatContainer/DnDWrapper/FileUploadWarningModal/index.jsx
  • components/WorkspaceChat/ChatContainer/MemoriesSidebar/MemoryModal/index.jsx — autoFocus/caret preserved
  • components/WorkspaceChat/ChatContainer/PromptInput/LLMSelector/SetupProvider/index.jsx — portal target changed body→#root
  • components/WorkspaceChat/ChatContainer/PromptInput/ToolsMenu/Tabs/SlashCommands/SlashPresets/AddPresetModal.jsx
  • components/WorkspaceChat/ChatContainer/PromptInput/ToolsMenu/Tabs/SlashCommands/SlashPresets/EditPresetModal.jsx
  • components/CommunityHub/PublishEntityModal/index.jsx — shell (variant="bare")
  • components/CommunityHub/PublishEntityModal/SystemPrompts/index.jsx
  • components/CommunityHub/PublishEntityModal/AgentFlows/index.jsx
  • components/CommunityHub/PublishEntityModal/SlashCommands/index.jsx
  • components/CommunityHub/UnauthenticatedHubModal/index.jsx
  • pages/Admin/Agents/AgentSkillSettings/index.jsx
  • pages/Admin/Agents/SQLConnectorSelection/SQLConnectionModal.jsx — keeps container portal + noPortal
  • pages/Admin/ExperimentalFeatures/index.jsx — TOS forced-choice modal
  • pages/Admin/Invitations/index.jsx
  • pages/Admin/Invitations/NewInviteModal/index.jsx
  • pages/Admin/SystemPromptVariables/index.jsx
  • pages/Admin/SystemPromptVariables/AddVariableModal/index.jsx
  • pages/Admin/SystemPromptVariables/VariableRow/index.jsx
  • pages/Admin/SystemPromptVariables/VariableRow/EditVariableModal/index.jsx
  • pages/Admin/Users/index.jsx
  • pages/Admin/Users/NewUserModal/index.jsx
  • pages/Admin/Users/UserRow/index.jsx
  • pages/Admin/Users/UserRow/EditUserModal/index.jsx
  • pages/Admin/Workspaces/index.jsx
  • pages/Admin/Workspaces/NewWorkspaceModal/index.jsx
  • pages/GeneralSettings/ApiKeys/index.jsx
  • pages/GeneralSettings/ApiKeys/NewApiKeyModal/index.jsx
  • pages/GeneralSettings/BrowserExtensionApiKey/index.jsx
  • pages/GeneralSettings/BrowserExtensionApiKey/NewBrowserExtensionApiKeyModal/index.jsx
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/ChatRow/index.jsx — TextPreview
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/index.jsx
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/NewEmbedModal/index.jsx
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/EmbedRow/index.jsx
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/EmbedRow/EditEmbedModal/index.jsx
  • pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/EmbedRow/CodeSnippetModal/index.jsx
  • pages/GeneralSettings/Chats/ChatRow/index.jsx — TextPreview
  • pages/GeneralSettings/EmbeddingPreference/index.jsx
  • pages/GeneralSettings/EmbeddingTextSplitterPreference/index.jsx
  • components/ChangeWarning/index.jsx — shared warning modal for the 3 embedding/vector pages
  • pages/GeneralSettings/MobileConnections/ConnectionModal/index.jsx — bespoke promo, variant="bare"
  • pages/GeneralSettings/ModelRouters/LLMProviderModelPicker/index.jsx — ProviderSetupModal
  • pages/GeneralSettings/ModelRouters/NewRouterModal/index.jsx
  • pages/GeneralSettings/ModelRouters/RuleBuilder/RuleForm/index.jsx — two-column
  • pages/GeneralSettings/ScheduledJobs/index.jsx
  • pages/GeneralSettings/ScheduledJobs/JobFormModal/index.jsx
  • pages/GeneralSettings/VectorDatabase/index.jsx
  • pages/Invite/index.jsx
  • pages/Invite/NewUserModal/index.jsx
  • pages/WorkspaceSettings/Members/index.jsx
  • pages/WorkspaceSettings/Members/AddMemberModal/index.jsx
  • pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/AgentLLMItem/index.jsx — SetupProvider portal + noPortal
  • pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/WorkspaceLLMItem/index.jsx — SetupProvider portal + noPortal

@shatfield4
shatfield4 marked this pull request as ready for review June 10, 2026 00:29
@shatfield4 shatfield4 changed the title Modal component Uniform modal component Jun 10, 2026

@angelplusultra angelplusultra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice job!

Just a couple nits but I tested 38 modal paths and everything seems to work great.

Comment thread frontend/src/components/CommunityHub/PublishEntityModal/index.jsx Outdated
Comment thread frontend/src/components/CommunityHub/PublishEntityModal/index.jsx Outdated
Comment thread frontend/src/components/CommunityHub/PublishEntityModal/index.jsx Outdated
Comment thread frontend/src/components/lib/Modal/index.jsx Outdated

@angelplusultra angelplusultra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

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