Nextjs with Styled components not passing theme

Viewed 1203

I'm trying to pass my theme object to styled-components on my Next.js project, but it keep's failing to receive it as a props.

That's my _document.tsx

import { getInitialProps } from "@expo/next-adapter/document";
import Document,  { DocumentContext, DocumentInitialProps }  from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

After that I wrapped my _app.tsx with the ThemeProvider

import Layout from '../components/Layout'
import 'setimmediate';
import { ThemeProvider } from 'styled-components';
import { wrapperStore } from "../store";
import { ApolloProvider } from "@apollo/client";
import client from './api/apollo-client';
import React from 'react';
import lightTheme from '../helpers/light-mode';
import { AppProps } from 'next/app';

function MyApp({ Component, pageProps }: AppProps) {

  return (
    <React.Fragment>
    <ApolloProvider client={client}>
      <ThemeProvider theme={lightTheme}>
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </ThemeProvider>
     </ApolloProvider>
    </React.Fragment>
  )
}
export default wrapperStore.withRedux(MyApp);

From here I receive a warning when I try to wrap my component, exporting it withTheme

[withTheme] You are not using a ThemeProvider nor passing a theme prop or a theme in defaultProps in component class "Connect(Front)"

when I try to console log theme from my props, it returns undefined, and when I create a styled component, trying to use theme as props it causes an error

export const RecruitmentTextLocation = styled.Text`
    fontSize: ${scaleFont(15)};
    textAlign: left;
    marginTop: ${scale(5)}px;
    marginBottom: ${scale(1)}px;
    fontFamily: roboto;
    fontWeight: 500;
    color: ${({theme}) => theme.colors.cardTitleColor};
`;

TypeError: Cannot read property 'colors' of undefined

I'm really stuck on how I can use theming with styled-components on Nextjs.

2 Answers

I suppose you problem is in light-mode.tsx. How can i see you use typescript in that case need create a declarations file and DefaultTheme interface. example

Create a declarations file TypeScript definitions for styled-components can be extended by using declaration merging since version v4.1.4 of the definitions. documentation

light-mode.tsx

import { DefaultTheme } from 'styled-components';

export const lightTheme: DefaultTheme = {
  colors: {
    cardTitleColor: red;
  }
};

I was looking for the same and found a solution for typing the theme object you receive as prop on your styled components.

First, export the types of your themes, e.g.:

export type LightTheme = typeof lightTheme;

Then add a src/declaration.d.ts file with the below, so to enhance the DefaultTheme exported by styled-components to be typed with your custom theme object:

import { Theme } from "globalStyles";

declare module "styled-components" {
  export interface DefaultTheme extends Theme {}
}

From there you won't need any withTheme to use your theme object, as you will simply be able to access it through:

color: ${({theme}) => theme.colors.cardTitleColor};
Related