Unable to style imported component "Identifier 'Header' has already been declared"

Okay so here’s the issue. I’m working on this theme. Here’s my index.js

import React from "react";
import { Global, css, connect, styled, Head } from "frontity";
import Header from "./header.js";
import Archive from "./Archive";
import Post from "./post.js";
import Page404 from "./page404.js";
import Loading from "./loading.js";
import Page from "./Page/Page.js";
import { media } from "./utilities/mixins";

const Theme = ({ state }) => {
  const data = state.source.get(state.router.link);

  return (
    <>
      <Head>
        <title>{state.frontity.title}</title>
        <meta name="description" content={state.frontity.description} />
        <html lang="en" />
      </Head>
      <Global styles={globalStyles} />
      <HeadContainer className="header">
        <Header />
      </HeadContainer>
      <Body className="content-body">
        {data.isFetching && <Loading />}
        {data.isArchive && <Archive />}
        {(data.isPage && <Page />) || (data.isPostType && <Post />)}
        {}
        {data.is404 && <Page404 />}
      </Body>
    </>
  );
};

export default connect(Theme);
//- CSS
// GLOBAL STYLES
const globalStyles = css`
  @import url("https://fonts.googleapis.com/css?family=Space+Mono:400,400i,700,700i&display=swap");

  :root {
    --primary: #1f38c5;
    --snappy: cubic-bezier(0.075, 0.82, 0.165, 1);
    --heavy-snap: cubic-bezier(0.6, -0.28, 0.735, 0.045);
  }

  body {
    margin: 0;
    font-family: "Space Mono", "Segoe UI", Roboto, "Droid Sans",
      "Helvetica Neue", Helvetica, Arial, sans-serif;
    box-sizing: border-box;
  }
  a,
  a:visited {
    color: inherit;
    text-decoration: none;
  }
`;


const HeadContainer = styled.header`
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  padding: 24px;
  color: black;
  display: flex;
  justify-content: space-between;
`;

const Body = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

and here is my header.js file

import React from "react";
import { connect, styled } from "frontity";
import Link from "./link";
import Nav from "./nav";
// import * as palette from "./utilities/variables";

const Header = ({ state }) => (
  <>
    <HomeLogo className="home-logo" link="/">
      {state.frontity.title}
    </HomeLogo>
    <Nav />
  </>
);

export default connect(Header);

const HomeLogo = styled(Link)`
  white-space: nowrap;
  color: black;
  display: block;
  font-size: 1.5em;
  font-weight: bold;
  transition: all 0.15s var(--heavy-snap);
  border-bottom: 3px solid transparent;
  padding: 0.1em 0.25em 0 0.25em;
  margin: auto 0.25em;
  display: inline;

  &:hover {
    border-bottom: 3px solid var(--primary);
    transition: all 0.15s var(--heavy-snap);
  }
`;

This currently works, and it produces the intended html markup:

<header class="header css-ot1its">
    <a href="/" class="home-logo css-17y2no6">
        t3 labs
    </a>
    <nav class="nav-list css-11kw5ec">
        <a href="/" class="css-3jufar">
            blog
        </a>
        <a href="/about-us/" class="css-hvaal0">
            about-us
        </a>
    </nav>
</header>

But I would like to make the actual mark up in index.js cleaner.

Instead of

<HeadContainer className="header">
        <Header />
      </HeadContainer>

I’d like to make it

<Header className="header" />

But when I remove the HeadContainer (and change the styled component from HeadContainer to Header) I get the following error:

  ERROR in ./packages/t3-labs/src/components/header.js
    Module build failed (from ./node_modules/babel-loader/lib/index.js):
    SyntaxError: /Users/aslan.french/work/server-front/packages/t3-labs/src/components/header.js: Identifier 'Header' has already been declared

I understand that I am getting this error because I declare “Header” both here:

import Header from "./header.js";

and here:

const Header= styled.header`
 width: 100%;
 max-width: 100%;
 box-sizing: border-box;
 padding: 24px;
 color: black;
 display: flex;
 justify-content: space-between;
`

because I can get the error to stop by either renaming the Header Component or the styled-component declaration, but I don’t understand what I should to if I want to import a component and then add styled-component stylings to it without wrapping it in a container component, which I find introduces too many unecessary layers of HTML elements. (I’ve mitigated this in the final HTML by using fragments but the question remains in the hypothetical. )

Suggestions?

In this case I’d have done something like this:

// header.jsx

import React from "react";
import { connect, styled } from "frontity";
import Link from "./link";
import Nav from "./nav";

const Header = ({ state }) => (
  <Container className="header">
    <HomeLogo className="home-logo" link="/">
      {state.frontity.title}
    </HomeLogo>
    <Nav />
  </Container>
);

export default connect(Header);

const Container = styled.header`
  /* your styles */
`;

const HomeLogo = styled(Link)`
 /* your styles */
`;
// theme.jsx

import Header from "./header.js";

const Theme = ({ state }) => {
  const data = state.source.get(state.router.link);

  return (
    <>
      {...}
      <Header />
      {...}
    </>
  );
};

Also, I don’t know if you’ll need those classes you are defining to style the elements somewhere else, but it kind of defeats one of the purposes of CSS-in-JS, avoiding mapping className everywhere. I’d suggest to remove them.

However, if what you want is to style a component once imported, and not when it’s defined, you can do something like this:

import Header from './header';
import { styled } from 'frontity';

const Theme = () => {
  return (
    <>
      { ... }
      <StyledHeader />
      { ... }
    </>
  );
}

export Theme;

const StyledHeader = styled(Header)`
 /* your styles */
`;

or

// theme.jsx

import Header from './header';
import { css } from 'frontity';

const Theme = () => {
  const headerStyles = css`
    /* your styles for header */
  `;

  return (
    <>
      { ... }
      <Header css={headerStyles} />
      { ... }
    </>
  );
}

export Theme;

Note that the component that receives the styles must be ready for it, so you need to map the className prop. In this case it would be:

const Header = ({ className }) => (
  <header className={className}>
    { ... }
  </header>
);

What’s going on here, if I remember right, is that the css prop passed to Header is being transpiled into className, therefore you need to map it to the outer element of your Header component.

I hope this helps! :slight_smile:

1 Like

I’m mostly just putting those class names for readiability purposes. It’s kinda of hard to diagnose problems in Chrome Dev Tools when everything is just <div class="css234789234">

This is probably the cleaner way to do things. The only ting I dislike is having to use a Container component. In the end the html that it produces is the same though and it more properly situates the styling of the component to it’s actual component jsx file instead of putting it in index.js, so I think I’ll follow this pattern you’ve presented. Thank you!

1 Like

For that purpose emotion is supposed to have a setting to add the React component name to the class in development, but it wasn’t working on the first version of Frontity. I don’t know the status on that now. Maybe is something fixable.

1 Like

Yeah that’s in process of being fixed here I believe: https://github.com/frontity/frontity/pull/227

1 Like

Hey guys! Just to let you know ,that PR was already merged and released :slightly_smiling_face: . You may need to update Frontity by the way. Here you have the guide in case you have any questions.

Please let us know how it goes :blush: