Skip to content

Commit

Permalink
fix(sbb-select): adapt setup to work with Next.js hydration (#2270)
Browse files Browse the repository at this point in the history
`<sbb-select>` causes a hydration error in Next.js. This PR implements a workaround by using the render logic of `@lit/react` to run our setup logic only after Next.js hydration or directly, if not in a Next.js environment.
  • Loading branch information
kyubisation committed Dec 7, 2023
1 parent 141941c commit be8a5c5
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/components/core/dom/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,6 @@ export const isAndroid = (): boolean =>
/** Whether the current browser is Safari. */
export const isSafari = (): boolean =>
isBrowser() && /safari/i.test(navigator.userAgent) && isWebkit();

/** Whether the application is being rendered in a Next.js environment. */
export const isNextjs = (): boolean => !!globalThis.next;
4 changes: 3 additions & 1 deletion src/components/datepicker/datepicker/datepicker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ describe('sbb-datepicker', () => {
expect(input).not.to.have.attribute('data-sbb-invalid');
});

it('should interpret valid values and set accessibility labels', async () => {
it('should interpret valid values and set accessibility labels', async function () {
// This test is flaky on Firefox, so we retry a few times.
this.retries(3);
const testCases = [
{
value: '5.5.0',
Expand Down
35 changes: 29 additions & 6 deletions src/components/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
toggleDatasetEntry,
getDocumentWritingMode,
setAttribute,
isNextjs,
} from '../core/dom';
import { ConnectedAbortController, EventEmitter } from '../core/eventing';
import {
Expand Down Expand Up @@ -231,12 +232,27 @@ export class SbbSelect extends UpdateScheduler(LitElement) {

// Wait for ssr hydration
this.startUpdate();
setTimeout(() => {
this._setupOrigin();
this._setupTrigger();
this._didLoad = true;
this.completeUpdate();
});
if (!isNextjs()) {
this._setupSelect();
}
}

/**
* Removes element's first attribute whose qualified name is qualifiedName.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute)
* @internal We need to override this due to a hydration issue with Next.js.
*/
public override removeAttribute(qualifiedName: string): void {
// In Next.js the hydration needs to finish before we can manipulate the light DOM.
// @lit/react calls removeAttribute('defer-hydration') in a useLayoutEffect,
// which is done after hydration is finished. Due to this we intercept this call
// in overriding removeAttribute to finish initialization of the sbb-select.
// https://github.com/lit/lit/blob/main/packages/react/src/create-component.ts#L293-L296
if (isNextjs() && qualifiedName === 'defer-hydration') {
this._setupSelect();
}
super.removeAttribute(qualifiedName);
}

public override connectedCallback(): void {
Expand Down Expand Up @@ -291,6 +307,13 @@ export class SbbSelect extends UpdateScheduler(LitElement) {
);
}

private _setupSelect(): void {
this._setupOrigin();
this._setupTrigger();
this._didLoad = true;
this.completeUpdate();
}

/** Sets the originElement; if the component is used in a sbb-form-field uses it, otherwise uses the parentElement. */
private _setupOrigin(): void {
const formField = this.closest?.('sbb-form-field');
Expand Down

0 comments on commit be8a5c5

Please sign in to comment.