Skip to content

refactor(fuselage): components take no styling props - #42974

Draft
ggazzo wants to merge 236 commits into
developfrom
docs/fuselage-component-style-props
Draft

ggazzo wants to merge 236 commits into
developfrom
docs/fuselage-component-style-props

Conversation

@ggazzo

@ggazzo ggazzo commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Proposed changes (including videos or screenshots)

Fuselage components stop taking Box styling props from their callers. A component accepts DOM/ARIA attributes and the variations it declares (no margins, sizes, flex-child props, colours, free is or rcx-* props), and the container owns the layout, mostly through gap. The rule and its reasoning are in docs/proposals/fuselage-component-style-props.md.

The pull request has three parts:

  1. The lock (first commit). packages/fuselage/scripts/scan-style-props.mjs lists every use of a Fuselage component that passes a styling prop it doesn't declare, and every element laid out by Margins/Scrollable. The lint job in .github/workflows/ci-code-check.yml runs it with --max, so the count can only go down. It starts at --max 914, the count on develop, and can be merged on its own.

  2. The migration. One commit per component or family moves spacing to gap on the container, sizing and flex-child props to the parent's layout, and spacing that a component should own into its own styles. Fuselage's own compositions get the same treatment.

  3. The variations the migration needed. These are declared on the components instead of passed as Box props:

    • Stack and PopoverSurface;
    • Divider flush/light/vertical sizes;
    • Button compact, ButtonGroup stretch='equal', IconButton badgePosition/color;
    • Chip small/label, Tile flush;
    • Table columns and TableCell rowHeader;
    • Icon color (semantic tokens), Skeleton inverted;
    • InputBox endAddonFlush, FieldRow justify;
    • Modal sizing, ModalIcon variant.

    is is narrowed where it is legitimate: Button/IconButton to 'button' | 'a', TableCell to 'td' | 'th'.

The last two commits lower --max to what is left and merge the pull request's changesets into one.

develop this branch
Scan findings 914 1

The one finding left, the ContactInfo conflicts Callout, stays on purpose: centring its icon would need a new Callout API.

Visible changes are small and were reviewed one by one in Storybook. Most layouts are pixel-identical. The intended differences are covered by the visual regression baselines updated in this branch, and are listed in the changeset.

Issue(s)

https://rocketchat.atlassian.net/browse/ARCH-2573

Steps to test or reproduce

  • CI: the lint job runs the scan. node packages/fuselage/scripts/scan-style-props.mjs --max 1 passes, and adding a styling prop to any Fuselage component makes it fail.
  • Storybook: the Fuselage visual regression suite covers the changed and the new components.
  • In the app, the screens with visible changes are:
    • the room header;
    • message attachments and UiKit blocks;
    • admin forms and settings;
    • the omnichannel filters and contact info;
    • the Marketplace;
    • login and registration.

Further comments

Merge order: the first commit (scanner and CI step) can be merged alone first, then the rest.

@ggazzo ggazzo added this to the 9.0.0 milestone Oct 20, 2026
@dionisio-bot

dionisio-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is still a draft
  • This PR is missing the 'stat: QA assured' label
  • GitHub is still computing mergeability — this will refresh shortly

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bd7afeb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@rocket.chat/fuselage Minor
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/layout Patch
@rocket.chat/meteor Patch
@rocket.chat/onboarding-ui Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-composer Patch
@rocket.chat/ui-voip Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/core-typings Patch
@rocket.chat/fuselage-forms Patch
@rocket.chat/fuselage-toastbar Patch
@rocket.chat/gazzodown Patch
@rocket.chat/storybook-config Patch
@rocket.chat/ui-account Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-conference Patch
@rocket.chat/ui-media Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/ui-livekit Patch
@rocket.chat/rest-typings Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.66804% with 222 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.97%. Comparing base (adb6b3b) to head (bd7afeb).
⚠️ Report is 3 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #42974      +/-   ##
===========================================
+ Coverage    71.49%   71.97%   +0.48%     
===========================================
  Files         5295     3284    -2011     
  Lines       228091   183904   -44187     
  Branches     42119    30214   -11905     
===========================================
- Hits        163078   132369   -30709     
+ Misses       59794    50146    -9648     
+ Partials      5219     1389    -3830     
Flag Coverage Δ
e2e ?
e2e-api ?
unit 71.97% <81.66%> (+0.42%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ggazzo
ggazzo force-pushed the docs/fuselage-component-style-props branch from 5e87038 to 143f1dc Compare October 22, 2026 00:35
@ggazzo ggazzo added the preview Builds a UI preview that Rocket.Chat Desktop can load label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🖥️ UI preview

Built from bd7afeb and published to ghcr.io/rocketchat/rocket.chat-web:pr-42974.

In Rocket.Chat Desktop with Developer Mode on, open one of these links to load this PR's UI into the workspace in focus:

Latest build of this PR rocketchat://ui-preview?pr=42974
This exact build rocketchat://ui-preview?pr=42974&sha=bd7afeb9b366de131f6ac68e1841f6c637c31d02

To pick the workspace, add &host=https://your.server. Use View > Restore server UI, or restart the app, to go back.

Or run it in a browser against any server (default https://open.rocket.chat):

npx @rocket.chat/ui-preview 42974 --server https://open.rocket.chat

ggazzo added 16 commits October 22, 2026 18:21
CI runs it in the lint job with --max, so the count of styling props passed to Fuselage components cannot grow while they are migrated.
Three of them (rcx-swiper-zoom-*, rcx-sidebar-item__menu, rcx-button--loading) match no CSS rule and are removed. rcx-field-group__item is still needed on CustomFieldsForm's Field, since FieldGroup patches the class onto CustomField, which doesn't forward it; it becomes a className.
AbacPreviewMemberGroup passed marginBlock={8}, which is the margin Divider already has.
Dividers that carried their own block margin or width now sit in containers whose gap and alignment produce the same layout.
Spacing moves to gap on the container (grouping siblings where only part
of them were spaced), ButtonGroup replaces per-button margins and width,
and flex-child props already implied by ButtonGroup stretch or the
parent's direction are dropped. Every change is pixel-identical.
Inputs that share a FieldRow with a remove button are grouped in a gap
Box, so the spacing lands only between them. Every change is
pixel-identical.
`flexGrow={1}` repeats the input's own default and `alignItems` lands on the
inner input when there is an addon, so both go away. Margins between a
TextInput and its siblings become `gap` on the row.
ggazzo added 26 commits October 22, 2026 23:10
FieldRow declares a justify variation that packs its content at the end of the line, for rows that hold a single trailing link.
The thread 'Also send to channel' label, the workspace and onboarding terms labels and the new-user password radio labels keep FieldLabel with its default typography, and the close-chat note becomes a FieldHint. The thread checkbox is inset by a padded Box instead of a Field margin, and the onboarding terms Field is spaced by its FieldGroup (it forwards the className the group patches in) or by its container's gap.
The custom emoji upload button and the canned response preview toggle move out of the FieldLabel into a FieldRow beside it, instead of laying the label out as a flex row.
The OAuth app forms and the app install page center their FieldGroup in a Box carrying the 600px column width, instead of passing the width to the FieldGroup.
…Row justify

The add-existing-channels Field is inset by a padded Box instead of its own margin, and the forgot-password links of the login form and the E2EE password modal use FieldRow justify='end'.
The migration leaves one finding, the ContactInfo conflicts Callout, so CI now fails on any new styling prop passed to a Fuselage component.
@ggazzo
ggazzo force-pushed the docs/fuselage-component-style-props branch from 476f070 to bff57bf Compare October 23, 2026 02:19
@ggazzo ggazzo changed the title docs(fuselage): propose that components take no styling props refactor(fuselage): components take no styling props Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Builds a UI preview that Rocket.Chat Desktop can load

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant