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: