Writing Better CSS with Design Systems

Writing Better CSS with Design Systems

In this CSS tutorial, Emily covers why design systems can help enable organizations to ship well-written CSS. She also covers what design systems are, the history of design systems at GitHub, and why we decided to abstract styles into reusable React components.

Authoring performant, scalable & accessible CSS is difficult and requires specialist knowledge. Emily covers why design systems can help enable organizations to ship well-written CSS. She also covers what design systems are, the history of design systems at GitHub, and why we decided to abstract styles into reusable React components. You will walk away with a deeper knowledge of how to design a public API for components, how theming works, and common pitfalls one might come across when trying to scale a design system across an organization.

Slide Page CSS Transition on React with React Router

Slide Page CSS Transition on React with React Router

Slide Page CSS Transition on React with React Router. We will be creating a CSS Page Slide Transition so one page slides on top of the other when navigating through pages. We will not cover how to set up or use React router so I assume you already have a working application with a multipage setup with react-router-dom.

Getting Started

One of the awesome things you can add to your application, for example, your Portfolio as a developer and software engineer so you want to make it look absolutely stunning by adding smooth animations and uniquely different design alongside that making the transition between your pages with animation can grab a lot of intention to you and your app plus it will give the user a much better experience compared to a regular application.

React Router uses a declarative page navigation which means that all the transition among your web pages are done on the client side, the server doesn't know or care about those navigations so in this case it can give you a lot of benefits adding to your apps for having a nice and elegant transition (Animation) when navigating between pages.

We will be using react-transition-group which allows you to add animations before and after a react element gets mounted or unmounted from the DOM it does handle all the logic of keeping track if the component behind the scenes all you have to do is to tell which component is going to be animated and what type of animation to be applied.

you can use regular react transition group animation or much better you can rely on a CSS Animation since you may already be familiar with plus it is super easy. We will be creating a CSS Page Slide Transition so one page slides on top of the other when navigating through pages.

So, first, install react-transition-group and install node-sass for using SASS with your react-create-app project.

npm install react-transition-group --save 

And node-sass

npm install node-sass --save-dev 

We will not cover how to set up or use React router so I assume you already have a working application with a multipage setup with react-router-dom.

You can get the Full Working Source Code on Github.

Use React Transition Group

We need to setup react transition group to work with react router so when it detects a location change (basically navigating to another page) it applies the specified animation.

Here is how my simple app looks like with react router only.

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }

  render() {
    const { location } = this.props;

    return (
      <div className="App">
        <Switch location={location}>
          <Route path="/" exact component={HomePage} />
          <Route path="/about" exact component={AboutPage} />
        </Switch>
      </div>
    );
  }
}

Basically, there are two pages the Home page and About page.

Let's wrap it up with React Transition Group component.

 render() {
    const { location } = this.props;
  /*Used to track if the page path did change so when can re-render the routes to apply animation */
    const currentKey = location.pathname.split("/")[1] || "/";
    //Specify the duration of the animation (on enter and on exit)
    const timeout = { enter: 800, exit: 400 };

    return (
      <TransitionGroup component="div" className="App">
        <CSSTransition
          key={currentKey}
          timeout={timeout}
          classNames="pageSlider"
          mountOnEnter={false}
          unmountOnExit={true}
        >
          <div>
            <Switch location={location}>
              <Route path="/" exact component={HomePage} />
              <Route path="/about" exact component={AboutPage} />
            </Switch>
          </div>
        </CSSTransition>
      </TransitionGroup>
    );
  }

The CSSTransition component will apply the specified CSS transition class through className prop plus it also takes a timeout object to know the duration of the transition on entering and on exit.

CurrentKey is used to keep track if the current page path has been changed so we can re-render the CSStransition group through the React key prop which it detects if the key value changes it re-renders current component and of course that will allow us to apply the transition animation whenever we navigate to a different page on the routes list.

Although, this is a slide animation but it is not smart enough to know either to apply transition from left to right or vice versa from right to left which is linked to the current page, for example if you're at the Home Page and you navigated to about page the page should apply transition from right to left since the Home page in this case is concerned as a base 0 path, in the other hand if you suddenly decided to move back to home page then you should expect the transition direction to be from left to right to make it feel a bit smarter other than always applying the same animation direction for whatever page path throughout your app.

So let's add a method for calculating the current page depth, depth is the number of paths exists in a URL so, for example, the root path "/" has a depth of 0 since there is an empty path, where for the "/about" page route it has a depth of 1.

getPathDepth(location) {
  let pathArr = location.pathname.split("/");
  pathArr = pathArr.filter(n => n !== "");
  return pathArr.length;
}

We want to have a prevDepth and then compare it with current depth to decide the transition's direction.

constructor(props) {
  super(props);
  this.state = {
    //Get initial depth of current page 
    prevDepth: this.getPathDepth(this.props.location)
  };
}

componentWillReceiveProps() {
  //When props are updated, update the current path 
  //props supplies us with the location object which has a router location info
  this.setState({ prevDepth: this.getPathDepth(this.props.location) });
}
CSS Slide Transition

Let's add the CSS Transition which is going to be responsible for animating and applying the smooth slide animation between pages.

You can create a new folder name it pageTransitions and put all of your transitions in there, create a new slideTransition.scss file (you can use regular CSS) but it is easier and faster to do it with SASS.

/* slideTransition.scss */

//old page exiting, hides it underneath (bottom) 
.pageSlider-exit > .page {
  z-index: 1;
}
//new page entering, show it on top
.pageSlider-enter > .page {
  z-index: 10;
}
//LEFT transition transform 100% to the right
.pageSlider-enter.left > .page {
  transform: translate3d(100%, 0, 0);
}
//RIGHT transition transform -100% to the left
.pageSlider-enter.right > .page {
  transform: translate3d(-100%, 0, 0);
}
//old exit left direction
.pageSlider-exit.left > .page {
  transform: translate3d(-100%, 0, 0);
}
//old exit right direction 
.pageSlider-exit.right > .page {
  transform: translate3d(100%, 0, 0);
}
//Enter is active (Page has finished transitioning) make it settle down 
.pageSlider-enter.pageSlider-enter-active > .page {
  transform: translate3d(0, 0, 0);
  //Apply all transitions 
  transition: all 800ms ease-in-out;
}

Regarding this pattern the CSSTransition works and read your CSS supplied transition class, you can easily create your own custom transitions and animation like fading or dissolve.

If you can notice we're adding a .page class to get the CSS code to be applied on, so now for every page we want to apply the animation to we need to add .page class to its classNames list.

Make it Smarter

On real time we need to decide either to move from left to right or from right to left by comparing the previous page depth which is in the state with the current depth.

<div
  className={
    this.getPathDepth(location) - this.state.prevDepth >= 0
      ? "left"
      : "right"
  }
>
  <Switch location={location}>
    <Route path="/" exact component={HomePage} />
    <Route path="/about" exact component={AboutPage} />
  </Switch>
</div>

So we compare both depths and decide to use left if current depth is greater than the previous one which means we are not in the home page so we will be applying transition from left to right otherwise apply from right to left.

The left and right classes are the defined classes names in the page slider transition class.

Finally, add the page className to the pages you which to apply the transition to when navigating to or from other pages.


export default class HomePage extends React.Component {
  render() {
    return (
      <div className="page-container page">
         Page Content 
      </div>
   );
  }
}

Try to run your application and navigate about pages you should see a really smooth and nice sliding left/right animation between your pages.

How to Create a Timeline Component with React.js and CSS

How to Create a Timeline Component with React.js and CSS

How to Create a Timeline Component with ReactJS and CSS. In this React.js and CSS tutorial we're going to use ReactJS to create a wonderful Timeline Component. Also, we're going to use CSS to add some magic on top to make it look beautiful!

These days I've been working on a new page for my website. I wanted to have a Timeline to showcase some of my professional accomplishments over the years.

I did it for a couple of reasons:

  1. My future self will look back one day and say: "Wow... I remember the day when I did that! How happy I was to achieve that goal!". Our success is a journey, not a destination and I want to write down every goal that I achieve along the way
  2. It might attract more clients (we'll see how this goes 😄)
  3. In my opinion it is a different kind of portfolio. A unique portfolio, maybe? 😜

Nevertheless... Let's build something now!

In the picture above you can see what we're going to build today using React! Before we start let's break down the steps we need to take:

  1. Create the data that we'll need
  2. Create the TimelineItem component - each individual timeline entry
  3. Create a Timeline container - it will take the data and pass it down to the TimelineItems
  4. Style everything
Create the data

Before we move to actually create the React components we need to know exactly how the data is going to look so we can plan out the DOM structure.

For this Timeline app we're going to need an array of objects. We will call this array: timelineData.

Let's see how it might look:

[
    {
        text: 'Wrote my first blog post ever on Medium',
        date: 'March 03 2017',
        category: {
            tag: 'medium',
            color: '#018f69'
        },
        link: {
            url:
                'https://medium.com/@popflorin1705/javascript-coding-challenge-1-6d9c712963d2',
            text: 'Read more'
        }
    },
    {
        // Another object with data
    }
];

The properties are pretty straightforward, right? I used similar data to what I have on my timeline page, so we can say that this is production ready! 😆

Next, we'll build the TimelineItem component. This will use the data from the object above:

The TimelineItem component
const TimelineItem = ({ data }) => (
    <div className="timeline-item">
        <div className="timeline-item-content">
            <span className="tag" style={{ background: data.category.color }}>
                {data.category.tag}
            </span>
            <time>{data.date}</time>
            <p>{data.text}</p>
            {data.link && (
                <a
                    href={data.link.url}
                    target="_blank"
                    rel="noopener noreferrer"
                >
                    {data.link.text}
                </a>
            )}
            <span className="circle" />
        </div>
    </div>
);

We have the following tags:

  1. .timeline-item div - used as a wrapper. This div will have half the width of it's parent's width (50%) and every other .timeline-item div will be placed to the right side using the :nth-child(odd) selector
  2. .timeline-item-content div - another wrapper (more on why we need this in the styling section)
  3. .tag span - this tag will have a custom background color depending on the category
  4. the time/date and the text
  5. link - we will need to check this to see if a link is provided because we might not always want to have one
  6. .circle span - this tag will be used to place a circle on the middle line/bar

Note: Everything will make much more sense when we get to the CSS/styling part, but before that let's create the Timeline component:

The Timeline container

This component will basically map over the array and for each object it will create a TimelineItem component. We also add a small check to make sure that there is at least one element in the array:

import timelineData from '_path_to_file_';

const Timeline = () =>
    timelineData.length > 0 && (
        <div className="timeline-container">
            {timelineData.map((data, idx) => (
                <TimelineItem data={data} key={idx} />
            ))}
        </div>
    );

As mentioned above, the timelineData is the array of objects containing all the required information. In my case I stored this array in a file and I imported it here, but you can take this from your own database or from an API endpoint, it's up to you.

The CSS

Note that most of the wrappers will be flexbox containers because we can play around easier with their positioning. Let's start with the .timeline-container CSS:

.timeline-container {
    display: flex;
    flex-direction: column;
    position: relative;
    margin: 40px 0;
}

.timeline-container::after {
    background-color: #e17b77;
    content: '';
    position: absolute;
    left: calc(50% - 2px);
    width: 4px;
    height: 100%;
}

We're using the ::after selector to create that red line/bar in the middle of the .timeline-container. Using the calc() function we can position the line exactly in the middle by subtracting half of it's size (2px) from 50%. We need to do this because by default the left property positions it according to the left edge of an element and not the middle.

Now, let's move to the .timeline-item wrapper.

Below you can see an example of how these are positioned within their parent (the .timeline-container).

As you can see, every other wrapper goes to the right, and the inner wrapper (the .timeline-item-content) is taking less space - space given by the p tag which is inside it (mostly). Let's see the CSS for this:

.timeline-item {
    display: flex;
    justify-content: flex-end;
    padding-right: 30px;
    position: relative;
    margin: 10px 0;
    width: 50%;
}

.timeline-item:nth-child(odd) {
    align-self: flex-end;
    justify-content: flex-start;
    padding-left: 30px;
    padding-right: 0;
}

The key to this is that we use the :nth-child(odd) selector and we set the align-self property to flex-end which means: "Go to the right as much as you can"!

Because these wrappers are 50% in width, you can see that two of them take up the whole width. From now on, every time we want to style differently something in the right side, we'll have to use this approach.

Next, the .timeline-item-content wrapper:

.timeline-item-content {
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    border-radius: 5px;
    background-color: #fff;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    padding: 15px;
    position: relative;
    width: 400px;
    max-width: 70%;
    text-align: right;
}

.timeline-item-content::after {
    content: ' ';
    background-color: #fff;
    box-shadow: 1px -1px 1px rgba(0, 0, 0, 0.2);
    position: absolute;
    right: -7.5px;
    top: calc(50% - 7.5px);
    transform: rotate(45deg);
    width: 15px;
    height: 15px;
}

.timeline-item:nth-child(odd) .timeline-item-content {
    text-align: left;
    align-items: flex-start;
}

.timeline-item:nth-child(odd) .timeline-item-content::after {
    right: auto;
    left: -7.5px;
    box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.2);
}

We have a few things going on:

  1. This wrapper has a fixed width and also a max-width. This is because we want it to have some boundaries, meaning that if there are only a few words, we want the box to be at least 400px wide, but if there is a lot of text, it shouldn't take up the full space (the 50% from the .timeline-item wrapper) but the text should move on to the next line -> this is the reason we used this second wrapper: .timeline-item-content
  2. The text-align and align-items properties are used to push the inner elements to the left or to the right, depending on the parent
  3. The small arrow that points to the middle line is given by the styles applied on the ::after selector. Basically it is a box with a box-shadow applied on it that is rotated 45deg
  4. As mentioned above, we style the right side by selecting the parent with the :nth-child(odd) selector

Next up, all the inner elements:

.timeline-item-content .tag {
    color: #fff;
    font-size: 12px;
    font-weight: bold;
    top: 5px;
    left: 5px;
    letter-spacing: 1px;
    padding: 5px;
    position: absolute;
    text-transform: uppercase;
}

.timeline-item:nth-child(odd) .timeline-item-content .tag {
    left: auto;
    right: 5px;
}

.timeline-item-content time {
    color: #777;
    font-size: 12px;
    font-weight: bold;
}

.timeline-item-content p {
    font-size: 16px;
    line-height: 24px;
    margin: 15px 0;
    max-width: 250px;
}

.timeline-item-content a {
    font-size: 14px;
    font-weight: bold;
}

.timeline-item-content a::after {
    content: ' ►';
    font-size: 12px;
}

.timeline-item-content .circle {
    background-color: #fff;
    border: 3px solid #e17b77;
    border-radius: 50%;
    position: absolute;
    top: calc(50% - 10px);
    right: -40px;
    width: 20px;
    height: 20px;
    z-index: 100;
}

.timeline-item:nth-child(odd) .timeline-item-content .circle {
    right: auto;
    left: -40px;
}

Few things to note here:

  1. As you might have guessed, the .tag is positioned absolute because we want to keep it in the top left (or right) corner no matter what size is the box
  2. We want to add a small caret after the a tag to highlight that it is a link
  3. We create a .circle and position it on top of the middle line/bar directly in front of the arrow

We're almost done! 😄 The only thing that's left to do is to add the CSS to make everything responsive across all screen sizes:

@media only screen and (max-width: 1023px) {
    .timeline-item-content {
        max-width: 100%;
    }
}

@media only screen and (max-width: 767px) {
    .timeline-item-content,
    .timeline-item:nth-child(odd) .timeline-item-content {
        padding: 15px 10px;
        text-align: center;
        align-items: center;
    }

    .timeline-item-content .tag {
        width: calc(100% - 10px);
        text-align: center;
    }

    .timeline-item-content time {
        margin-top: 20px;
    }

    .timeline-item-content a {
        text-decoration: underline;
    }

    .timeline-item-content a::after {
        display: none;
    }
}

We have two media queries:

  1. On small laptop screen sizes - max-width: 1023px - we want to allow the .timeline-item-content to go across the entire width of it's parent because the screen is smaller and otherwise it would look squeezed

  2. On phones - max-width: 767px

    • set the .tag to be full width (and for that we don't need to forget to subtract 10px from the total of 100% - this is because we have it positioned at left: 5px, so we remove double of this amount)
    • center all the text and push it down from the top just a little bit
    • remove the caret on the link and add an underline - looks better on mobile 😉

Aaaand... We're done!

Conclusion

As I mentioned, this component is on my Timeline page. Check it out to see it in action! 😄

If there is something that you didn't understand from this article, make sure you contact me and I'll be happy to answer your questions!

Happy Coding! 😇

How to Share Code Between React and React Native

How to Share Code Between React and React Native

Learn how to share code between React and React Native to avoid duplicating logic. Sharing Code Between React and React-Native: What Not to Share. This question of sharing code between React and React Native, in fact, one of the hot topics among React and React native developers all over the world. React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native.

How to Share Code Between React and React Native

Sharing Code Between React and React-Native: What Not to Share - Ben Ellerby

React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native. Yet this is not always the best approach. There is value in only sharing your business and state logic; keeping your render code separate.

In this talk I will give real examples from my work with MADE.COM, migrating their web and mobile application to React and React-Native with code sharing as a primary objective.

How to Share Code Between React and React Native

Learn how to share code between React and React Native to avoid duplicating logic

Sharing Code Between React and React Native

React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native. Yet this is not always the best approach. There is value in only sharing your business and state logic; keeping your render code separate.