Next.js: Link as styled component

Created on 11 May 2017  ·  18Comments  ·  Source: vercel/next.js

I followed #799 but couldn't get a clean way to have a styled-component link, I had to duplicate the href:

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

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

What's the proper way to make styled-component links?

Using next.js 2.3.1.

Most helpful comment

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 <a/> tag).

Using the first example of issue: it could be done this way:

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

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

All 18 comments

I had the exact problem when using an a tag without an href attribute in Chrome. It is not styled as a link and does not have the browsers accessibility features of a regular link. What worked was using an empty href on the a tag.

Experiencing this too.

For the workaround It's probably a better idea to include the href a second time rather than blank. If only for the browser url preview.

You can pass a component to styledcomponents instead of using a tag
https://github.com/styled-components/styled-components#third-party-components

import Link from 'next/link'
const StyledLink = styled(Link)`
  color: red;
  background: blue;
`

Use it

export default () => (<div><StyledLink href="mylink">MyText</StyledLink></div>)

Thanks @kennylavender, will try that!

@sedubois did that work? You can't pass className to a Link, so I don't think it will work

@luisrudge haven't tried yet, right now workaround was good enough and I'll try one more time to see if I can use styled-jsx directly...

If you confirm it doesn't work let me know and can reopen this.

@sedubois I can confirm that @kennylavender's solution does not work. I'd recommend reopening this issue.

A Pull Request could be made to allow the nextjs Link component to support this or you could create your own version nextjs Link Component that works with styledcomponents. Without looking at the link code it just sounds like its not passing any props through to the anchor element.

You could create your own by importing the nextjs Router and then allow styledcomponents to style the component https://www.styled-components.com/docs/basics#styling-any-components

Here is a quick example, I only wrote this code here directly and have not tested it so just use it only as an example.

// my-app-link.js
import React from 'react'
import PropTypes from 'prop-types' // Import this from react if your using an older version.
import Router from 'next/router'

const handler = (href) => Router.push(href);

const Link = ({className, children, href, ...rest}={}) => (
  <a onClick={() => handler(href)} className={className} {...rest} >{children}</a>
);

Link.propTypes = {
  className: PropTypes.string,
  href: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.string,
  ]),
  children: PropTypes.node,
}

export default Link;

Good approach @kennylavender but I don't think it is good enough, because you aren't rendering href attribute (you are using onClick event instead). So... How good is this approach for SEO? Other alternatives?

Its just an example you should take it further. You can and definitely should add a href attribute ontop of the code I posted. Take a look at how the nextjs/link is implemented to get an idea of how to do that.

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 <a/> tag).

Using the first example of issue: it could be done this way:

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

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

FYI: If you are using next-routes it would look like this:

export default ({route, params, children}) => (
  <Link route={route} params={params} passHref>
    <StyledLink>{children}</StyledLink>
  </Link>
)

Improved @vjpr solution, bypassing the className prop directly to our Link so we can extend their styles in the correct scope:

Link.js

export default ({ route, params, children, className }) => (
  <Link route={route} params={params} passHref>
    <StyledLink className={className}>{children}</StyledLink>
  </Link>
)

AnotherComponent.js

import Link fron 'components/Link';

const RedLink = styled(Link)`
  background-color: red;
`

A slightly improved version of @torresandres, styling the link inside the component so we don't have to create a styled component in every component we import Link to.

Link.js

const StyledLink = styled.a`
  //styles
`
export default ({ route, params, href, children, className }) => (
  <Link route={route} params={params} href={href} passHref>
    <StyledLink className={className}>{children}</StyledLink>
  </Link>
);

AnotherComponent.js

<Link href="/">Login</Link>

Is there any specific reason why className isn't available as a prop to Link? I'd love to make a PR to add that, but I figure there must be a reason why that isn't allowed.

Found the answer!
https://github.com/zeit/next.js/pull/1642#issuecomment-292431043

for people how want to change the style of Link with styled-components

const LinkItem = styled(Link)`
// your style
`;

then you can use like this <LinkItem to="/yourComponent">somthing</LinkItem>

It took me some time to figure this out so I'll write a TLDR 👇

TLDR Add passHref to your <Link> tag and include the styled components you want inside of it

Practical Example
In Parent Component:

<Link href="/login" passHref>
          <TopbarLink>Login</TopbarLink>
</Link>

In the styled component file that defines TopbarLink:

export const TopbarLink = styled.a`
// your style
`;

@ferrucc-io Your example wraps anchor within an anchor. And also normally you might need positioning the Link. Which brings the initial problem as its the inner one which is styled.

Was this page helpful?
0 / 5 - 0 ratings