Skip to content

feat(sidebar): align with fusion ds - #8145

Open
ibutakova wants to merge 1 commit into
masterfrom
FE-7507-align-sidebar-with-fusion-ds
Open

feat(sidebar): align with fusion ds#8145
ibutakova wants to merge 1 commit into
masterfrom
FE-7507-align-sidebar-with-fusion-ds

Conversation

@ibutakova

@ibutakova ibutakova commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Proposed behaviour

Updated Sidebar follows the latest responsive and visual design:

  • Use a fluid 30vw desktop width with a 288px minimum.
  • Cap explicit preset and custom widths at the viewport width.
  • Render Sidebar full-width with square corners at 768px and below.
  • Hide the modal dimmer at 768px and below.
  • Allow the complete mobile Sidebar, including form footers, to scroll as one region.
  • Use Fusion design tokens for backgrounds, borders, spacing, typography, depth.
  • Render string headers as semantic h1 elements and automatically associate string and custom-node headers with the dialog.
  • Add typical and inverse header variants while retaining light and dark as deprecated aliases.
  • Add the optional gradientKeyLine header treatment.
  • Deprecate position and preset size props while retaining explicit legacy values.

BREAKING CHANGE: Sidebars without an explicit size or width now use a fluid 30vw width with a 288px minimum instead of the 514px medium width. At 768px and below, Sidebars fill the viewport and hide the modal dimmer.

Current behaviour

Sidebar currently:

  • Defaults to the fixed medium width of 514px.
  • Uses legacy colour, spacing, border, shadow, and sizing tokens.
  • Retains its desktop presentation on small screens.
  • Uses light and dark header variants.
  • Requires consumers to construct their own semantic header content.
  • Does not support the optional AI gradient keyline treatment.

Checklist

  • Commits follow our style guide
  • Related issues linked in commit messages if required
  • Screenshots are included in the PR if useful
  • All themes are supported if required
  • Unit tests added or updated if required
  • Playwright automation tests added or updated if required
  • Storybook added or updated if required
  • Translations added or updated (including creating or amending translation keys table in storybook) if required
  • Typescript d.ts file added or updated if required
  • Related docs have been updated if required

QA

  • Tested in provided StackBlitz sandbox/Storybook
  • Add new Playwright test coverage if required
  • Carbon implementation matches Design System/designs
  • UI Tests GitHub check reviewed if required

Additional context

Testing instructions

  1. Open the default Sidebar at a viewport wider than 768px.
  • Confirm its width is 30vw, with a 288px minimum.
  • Confirm it is positioned on the right with rounded exposed corners.
  1. Set the viewport to 769px.
  • Confirm the default Sidebar remains 288px wide.
  • Confirm size=“extra-large” and oversized custom widths are capped at the viewport width.
  1. Set the viewport to 768px or narrower.
  • Confirm the Sidebar fills the viewport.
  • Confirm its corners are square and the modal dimmer is hidden.
  • Confirm long content and a form footer scroll together.
  1. Provide a string header.
  • Confirm it renders as an h1 and supplies the dialog’s accessible name.
  1. Provide a custom React-node header.
  • Confirm it supplies the dialog’s accessible name automatically.
  • Confirm explicit aria-label and aria-labelledby values still override the generated association.
  1. Check headerVariant=“typical” and headerVariant=“inverse”.
  • Confirm deprecated light and dark values retain their equivalent treatments.
  1. Enable gradientKeyLine.
  • Confirm the AI gradient divider appears without changing the accessible name.
  1. Open the Top Modal Override story.
  • Confirm the Sidebar remains the active top modal when other dialogs are mounted after it.
Screenshot 2026-08-23 at 21 25 05 Screenshot 2026-08-23 at 21 26 14 Screenshot 2026-08-23 at 21 26 41 Screenshot 2026-08-23 at 21 27 15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

Modernizes Sidebar to align with Fusion design, responsive behavior, and accessibility conventions.

Changes:

  • Adds fluid desktop and full-width mobile layouts using Fusion tokens.
  • Adds semantic header labeling, variants, gradient keyline, and deprecations.
  • Updates stories, documentation, and browser/unit coverage.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/components/sidebar/sidebar.component.tsx Updates API, accessibility, and modal integration.
src/components/sidebar/sidebar.style.ts Implements responsive and tokenized styling.
src/components/sidebar/sidebar.test.tsx Covers semantics, variants, and styles.
src/components/sidebar/sidebar.pw.tsx Tests responsive browser behavior.
src/components/sidebar/components.test-pw.tsx Updates Playwright fixtures.
src/components/sidebar/sidebar.stories.tsx Adds responsive and visual examples.
src/components/sidebar/sidebar-test.stories.tsx Updates visual test stories.
src/components/sidebar/sidebar.mdx Documents the updated API and behavior.
src/components/sidebar/__internal__/sidebar-header/sidebar-header.component.tsx Adds semantic titles and keyline rendering.
src/components/sidebar/__internal__/sidebar-header/sidebar-header.style.ts Applies header variants and Fusion tokens.
skills/carbon-react/components/sidebar.md Excluded from review by policy.
Files excluded by content exclusion policy (1)
  • skills/carbon-react/components/sidebar.md

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/components/sidebar/sidebar.style.ts
Comment thread src/components/sidebar/sidebar.component.tsx Outdated
Comment thread src/components/sidebar/sidebar.component.tsx
Comment thread src/components/sidebar/sidebar.style.ts
@ibutakova
ibutakova force-pushed the FE-7507-align-sidebar-with-fusion-ds branch 3 times, most recently from 4f9e8fa to 1c93c90 Compare August 27, 2026 12:02
Comment thread src/components/sidebar/__internal__/sidebar-header/sidebar-header.style.ts Outdated
Comment thread src/components/sidebar/sidebar.component.tsx Outdated
Comment thread src/components/sidebar/sidebar.stories.tsx
@ibutakova
ibutakova force-pushed the FE-7507-align-sidebar-with-fusion-ds branch from 1c93c90 to 0096cd0 Compare September 2, 2026 09:47
DipperTheDan
DipperTheDan previously approved these changes Sep 2, 2026
data-role="sidebar-header"
p="27px 32px 32px"
headerVariant={headerVariant}
p="var(--global-space-comp-xl)"

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.

suggestion, instead of passing padding down like this, we can just apply it directly in the css of the styled component.

You can do this here in StyledSidebarHeader and SidebarSubHeader, once these have been replaced you can also remove the padding import from styled-system in sidebar-header.style.ts

@ibutakova ibutakova Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If I remove that import as suggested, public headerPadding and subheaderPadding props stop doing anything.
But good catch on the approach 'p=...', I will move default padding to css, so this is handled in one place.

const inverse = $headerVariant === "inverse" || $headerVariant === "dark";

return css`
background-color: ${inverse

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.

nitpick: you could do the ternary inside a template literal like so

var(--container-standard-${inverse ? "inverse" : ""}-bg-default)

or something alone those lines to save a little bit of lines here, but what you have is fine and completely acceptable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggestion as literally written looks broken) Consider inverse = false => var(--container-standard**--**bg-default). The hyphens catch an eye and I think we accidentally can invite a morse code into our CSS)
If you insist on change, I can introduce const variant suffix = inverse ? "-inverse" : "". Do you think it worth it?

display: flex;
justify-content: space-between;
gap: var(--spacing200);
gap: var(--global-space-comp-l);

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.

question: should this gap be the same for all sizes, or should we not be using the component size to dictate this gap?

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.

Same comment applies to other fixed size usages in the PR 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let me double-check

color: var(--container-standard-inverse-txt-default);
}

&:hover ${StyledIcon}, &:active ${StyledIcon}, &:focus ${StyledIcon} {

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.

suggestion (non-blocking): you may be able to group these together like:

&:is(:hover, :active, :focus) ${StyledIcon} { color: ...; }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nice simplification, will apply it

Comment thread src/components/sidebar/sidebar.mdx Outdated

### Responsive behavior

At 768px and below, the Sidebar fills the viewport and scrolls its content regions together. Above 768px, it uses its desktop width and keeps a sticky footer visible while the content scrolls.

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.

suggestion: I think some of the content here is repeated as the same responsive behaviour is also mentioned above on line 33

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will update

subHeader,
position = "right",
size = "medium",
size,

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.

question: is there any reason why "medium" is no longer the default here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Size prop is now deprecated

};

const closeButton = renderCloseButton();
const hasHeader = Boolean(header);

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.

question: do we need these consts here? just checking the props presence seemed to be doing the job

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

They are justifed as used more than once, and make usage conditions in difference places clearer


test.describe("Focus management and interaction tests for Sidebar component", () => {
test("should render component with focusableContainers", async ({
test("allows an additional focusable container to remain interactive", async ({

@tomdavies73 tomdavies73 Sep 2, 2026

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.

question: more of a general question on the testing approach here, are there any tests below which you think may be better suited as static chromatic snapshots or interaction stories which trigger a chromatic snapshot?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree, visual layout should be covered by Chromatic, which is why ResponsiveBehaviour has snapshots on both sides of the breakpoints. But why playwright here - because these tests verify focus order, scrolling, modal-interactions - visual snapshot cannot prove that.
Good split to think about. Probably interaction stories can simulate tab/click sequence and even assert focus, for example, but they show nothing about which element has focus. I mean a human reviewing snapshot has to visually confirm, 'yes, that focus ring is on that button, and not not on the other button nearby'. Also, the other real constraint is sequencing, even not visibility. Consider test case, like 'when is opened, then closed, then ..., then check focus again', - it means capturing several focus movements in one flow, and this not always the same is capturing one state per story.
Still I prefer to align with team/project approach. Ping me if this case need to be reworked!

BREAKING CHANGE: Sidebars without an explicit size or width now use a fluid
30vw width with a 288px minimum instead of the 514px medium width. At 768px
and below, Sidebars fill the viewport and hide the modal dimmer
@ibutakova
ibutakova force-pushed the FE-7507-align-sidebar-with-fusion-ds branch from 33eb67c to 22c07e5 Compare September 10, 2026 12:38
@ibutakova
ibutakova marked this pull request as ready for review September 10, 2026 12:53
@ibutakova
ibutakova requested review from a team as code owners September 10, 2026 12:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

4 participants