L. Norman
L. Norman

Reputation: 483

Styled-components with components in Nextjs

I am setting up a simple Nextjs boilerplate but can't seem to get the styled-components to work. In my file Header.tsx:

// Core Module Imports
import Link from "next/link";
import * as React from "react";

// Styled-Component Imports
import styled from "../theme/theme";

class Header extends React.Component {
    render() {
        return (
            <div>
                <Link href="/about">
                   <a>About Us</a>
                </Link>
            </div>
        );
    }
}

const StyledHeader = styled(Header)`
    width: 100vw;
    height: 10vh;
    background: #2a2c39;
    color: #ff0000;
    link-style: none;
`;

export default StyledHeader;

As you can see, I set up a simple Header component and then below I used styled() to define my css. In my file Index.tsx:

// Core Module Imports
import * as React from "react";

import StyledHeader from "../components/Header";

class Index extends React.Component {
    render() {
        return (
            <div>
                <StyledHeader />
                <p>Test Change</p>
                <div>Example Div</div>
            </div>
        );
    }
}

export default Index;

Obviously I am doing something wrong because it is not working and all I get it an unstyled link. Can anyone point me in the right direction?

Upvotes: 4

Views: 9125

Answers (4)

Yves Boutellier
Yves Boutellier

Reputation: 2044

I don't know if this is what you're searching for but styling a Next Link is pretty easy

import Link from 'next/link'

const StyledLink = styled(Link)`
    text-decoration: none;
    color: white;
`

and then use it like

<StyledLink href={route.path}>
    {route.name}
</StyledLink>

Upvotes: 1

Justin Punzalan
Justin Punzalan

Reputation: 21

TL;DR:

Create a _document.js file in your /pages folder and paste this in. It should work immediately 😁

import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

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

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

If you want styled-components to work automatically on every page/component, you "can create a ServerStyleSheet and add a provider to your React tree, that accepts styles via a context API." In Nextjs, you would do so by adding it to your _document.js file...

You can read about it more if you follow these links:

  1. Styled-Components: SSR Documentation
  2. Nextjs: Customer Render Page

Thankfully there's already a working example you can use from the styled-components people themselves!

Check it out here: https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_document.js

Upvotes: 1

L. Norman
L. Norman

Reputation: 483

For anyone that sees this and has a similar issue, check out this: https://github.com/zeit/next.js/issues/1942#issuecomment-313925454

Fixed my issue.

Hey guys. At version 3.0.1-beta.13+, you could set passHref to Link (as a boolean property) to expose its href to styled-components (or any other library that wraps its tag).

const StyledLink = styled.a`
  color: red;
  background: blue;
`

export default ({ href, name }) => (
  <Link prefetch href={href} passHref>
    <StyledLink>{name}</StyledLink>
  </Link>
)

There are solutions in the GitHub issue for people using next-routes.

Upvotes: 3

SimpleJ
SimpleJ

Reputation: 14788

You need to pass this.props.className into the root element of Header so the styled wrapper can pass a generated class name in:

class Header extends React.Component {
    render() {
        return (
            <div className={this.props.className}>
                <Link href="/about">
                   <a>About Us</a>
                </Link>
            </div>
        );
    }
}

Upvotes: 2

Related Questions