Tag: Lines

Explain the First 10 Lines of Twitter’s Source Code to Me

For the past few weeks, I’ve been hiring for a senior full-stack JavaScript engineer at my rental furniture company, Pabio. Since we’re a remote team, we conduct our interviews on Zoom, and I’ve observed that some developers are not great at live-coding or whiteboard interviews, even if they’re good at the job. So, instead, we have an hour-long technical discussion where I ask them questions about web vitals, accessibility, the browser wars, and other similar topics about the web. One of the questions I always like to ask is: “Explain the first ten or so lines of the Twitter source code to me.”

I think it’s a simple test that tells me a lot about the depth of fundamental front-end knowledge they have, and this article lists the best answers.

For context, I share my screen, open Twitter.com and click View source. Then I ask them to go line-by-line to help me understand the HTML, and they can say as much or as little as they like. I also zoom in to make the text more legible, so you don’t see the full line but you get an idea. Here’s what it looks like:

Screenshot of source code from Twitter.

Note that since our technical discussion is a conversation. I don’t expect a perfect answer from anyone. If I hear some right keywords, I know that the candidate knows the concept, and I try to push them in the right direction.

Line 1: <!DOCTYPE html>

The first line of every document’s source code is the perfect for this interview because how much a candidate knows about the DOCTYPE declaration closely resembles how many years of experience they have. I still remember my Dreamweaver days with the long XHTML DOCTYPE line, like Chris listed in his article “The Common DOCTYPES” from 2009.

Perfect answer: This is the document type (doc-type) declaration that we always put as the first line in HTML files. You might think that this information is redundant because the browser already knows that the MIME type of the response is text/html; but in the Netscape/Internet Explorer days, browsers had the difficult task of figuring out which HTML standard to use to render the page from multiple competing versions.

This was especially annoying because each standard generated a different layout so this tag was adopted to make it easy for browsers. Previously, DOCTYPE tags were long and even included the specification link (kinda like SVGs have today), but luckily the simple <!doctype html> was standardized in HTML5 and still lives on.

Also accepted: This is the DOCTYPE tag to let the browser know that this is an HTML5 page and should be rendered as such.

Line 2: <html dir="ltr" lang="en">

This line in the source code tells me if the candidate knows about accessibility and localization. Surprisingly, only a few people knew about the dir attribute in my interviews, but it’s a great segue into a discussion about screen readers. Almost everyone was able to figure out the lang="en" attribute, even if they haven’t used it before.

Perfect answer: This is the root element of an HTML document and all other elements are inside this one. Here, it has two attributes, direction and language. The direction attribute has the value left-to-right to tell user agents which direction the content is in; other values are right-to-left for languages like Arabic, or just auto which leaves it to the browser to figure out.

The language attribute tells us that all content inside this tag is in English; you can set this value to any language tag, even to differentiate en-us and en-gb, for example. This is also useful for screen readers to know which language to announce in.

Line 3: <meta charset="utf-8">

Perfect answer: The meta tag in the source code is for supplying metadata about this document. The character set (char-set) attribute tells the browser which character encoding to use, and Twitter uses the standard UTF-8 encoding. UTF-8 is great because it has many character points so you can use all sorts of symbols and emoji in your source code. It’s important to put this tag near the beginning of your code so the browser hasn’t already started parsing too much text when it comes across this line; I think the rule is to put it in the first kilobyte of the document, but I’d say the best practice is to put it right at the top of <head>.

As a side note, it looks like Twitter omits the <head> tag for performance reasons (less code to load), but I still like to make it explicit as it’s a clear home for all metadata, styles, etc.

Line 4: <meta name="viewport" content="width=device-...

Perfect answer: This meta tag in the source code is for properly sizing the webpage on small screens, like smartphones. If you remember the original iPhone keynote, Steve Jobs showed the entire New York Times website on that tiny 4.5-inch screen; back then it was an amazing feature that you had to pinch to zoom to actually be able to read.

Now that websites are responsive by design, width=device-width tells the browser to use 100% of the device’s width as the viewport so there’s no horizontal scrolling, but you can even specify specific pixel values for width. The standard best practice is to set the initial scale to 1 and the width to device-width so people can still zoom around if they wish.

The screenshot of the source code doesn’t show these values but it’s good to know: Twitter also applies user-scalable=0 which, as the name suggests, disables the ability to zoom. This is not good for accessibility but makes the webpage feel more like a native app. It also sets maximum-scale=1 for the same reason (you can use minimum and maximum scale to clamp the zoom-ablity between these values). In general, setting the full width and initial scale is enough.

Line 5: <meta property="og:site_name" content="Twitt...

About 50% of all candidates knew about Open Graph tags, and a good answer to this question shows that they know about SEO.

Perfect answer: This tag is an Open Graph (OG) meta tag for the site name, Twitter. The Open Graph protocol was made by Facebook to make it easier to unfurl links and show their previews in a nice card layout; developers can add all sorts of authorship details and cover images for fancy sharing. In fact, these days it’s even common to auto-generate the open graph image using something like Puppeteer. (CSS-Tricks uses a WordPress plugin that does it.)

Another interesting side note is that meta tags usually have the name attribute, but OG uses the non-standard property attribute. I guess that’s just Facebook being Facebook? The title, URL, and description Open Graph tags are kinda redundant because we already have regular meta tags for these, but people add them just to be safe. Most sites these days use a combination of Open Graph and other metatags and the content on a page to generate rich previews.

Line 6: <meta name="apple-mobile-web-app-title" cont...

Most candidates didn’t know about this one, but experienced developers can talk about how to optimize a website for Apple devices, like apple-touch-icons and Safari pinned tab SVGs.

Perfect answer: You can pin a website on an iPhone’s homescreen to make it feel like a native app. Safari doesn’t support progressive web apps and you can’t really use other browser engines on iOS, so you don’t really have other options if you want that native-like experience, which Twitter, of course, likes. So they add this to tell Safari that the title of this app is Twitter. The next line is similar and controls how the status bar should look like when the app has launched.

Line 8: <meta name="theme-color" content="#ffffff"...

Perfect answer: This is the proper web standards-esque equivalent of the Apple status bar color meta tag. It tells the browser to theme the surrounding UI. Chrome on Android and Brave on desktop both do a pretty good job with that. You can put any CSS color in the content, and can even use the media attribute to only show this color for a specific media query like, for example, to support a dark theme. You can also define this and additional properties in the web app manifest.

Line 9: <meta http-equiv="origin-trial" content="...

Nobody I interviewed knew about this one. I would assume that you’d know this only if you have in-depth knowledge about all the new things that are happening on the standards track.

Perfect answer: Origin trials let us use new and experimental features on our site and the feedback is tracked by the user agent and reported to the web standards community without users having to opt-in to a feature flag. For example, Edge has an origin trial for dual-screen and foldable device primitives, which is pretty cool as you can make interesting layouts based on whether a foldable phone is opened or closed.

Also accepted: I don’t know about this one.

Line 10: html{-ms-text-size-adjust:100%;-webkit-text...

Almost nobody knew about this one too; only if you know about CSS edge cases and optimizations, you’d be able to figure this line out.

Perfect answer: Imagine that you don’t have a mobile responsive site and you open it on a small screen, so the browser might resize the text to make it bigger so it’s easier to read. The CSS text-size-adjust property can either disable this feature with the value none or specify a percentage up to which the browser is allowed to make the text bigger.

In this case, Twitter says the maximum is 100%, so the text should be no bigger than the actual size; they just do that because their site is already responsive and they don’t want to risk a browser breaking the layout with a larger font size. This is applied to the root HTML tag so it applies to everything inside it. Since this is an experimental CSS property, vendor prefixes are required. Also, there’s a missing <style> before this CSS, but I’m guessing that’s minified in the previous line and we don’t see it.

Also accepted: I don’t know about this property in specific but the -ms and -webkit- are vendor prefixes needed by Internet Explorer and WebKit-based browsers, respectively, for non-standard properties. We used to require these prefixes when CSS3 came out, but as properties go from experimental to stable or are adopted to a standards track, these prefixes go away in favor of a standardized property.

Bonus — Line 11: body{margin:0;}

This line from Twitter’s source code is particularly fun because you can follow-up with a question about the difference between resetting and normalizing a webpage. Almost everyone knew a version of the right answer.

Perfect answer: Because different browsers have different default styles (user agent stylesheet), you want to overwrite them by resetting properties so your site looks the same across devices. In this case, Twitter is telling the browser to remove the body tag’s default margin. This is just to reduce browser inconsistencies, but I prefer normalizing the styles instead of resetting them, i.e., applying the same defaults across browsers rather than removing them altogether. People even used to use * { margin: 0 } which is totally overkill and not great for performance, but now it’s common to import something like normalize.css or reset.css (or even something newer) and start from there.

More lines!

I always enjoy playing with the browser Inspector tool to see how sites are made, which is how I came up with this idea. Even though I consider myself sort of an expert on semantic HTML, I learn something new every time I do this exercise.

Since Twitter is mostly a client-side React app, there’s only a few dozen lines in the source code. Even with that, there’s so much to learn! There are a few more interesting lines in the Twitter source code that I leave as an exercise for you, the reader. How many of them could you explain in an interview?

<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Twitter">

…tells browsers that users can add Twitter as a search engine.

<link rel="preload" as="script" crossorigin="anonymous" href="https://abs.twimg.com/responsive-web/client-web/polyfills.cad508b5.js" nonce="MGUyZTIyN2ItMDM1ZC00MzE5LWE2YmMtYTU5NTg2MDU0OTM1" />

…has many interesting attributes that can be discussed, especially nonce.

<link rel="alternate" hreflang="x-default" href="https://twitter.com/" />

…for international landing pages.

:focus:not([data-focusvisible-polyfill]){outline: none;}

…for removing the focus outline when not using keyboard navigation (the CSS :focus-visible selector is polyfilled here).


Explain the First 10 Lines of Twitter’s Source Code to Me originally published on CSS-Tricks. You should get the newsletter.

CSS-Tricks

, , , , ,

A Calendar in Three Lines of CSS

This article has no byline and is on a website that is even more weirdly specific than this one is, but I appreciate the trick here. A seven-column grid makes for a calendar layout pretty quick. You can let the days (grid items) fall onto it naturally, except kick the first day over to the correct first column with grid-column-start.

Thoughts:

  • I’d go with an <ol> rather than a <ul> just because it seems like days are definitely ordered.
  • The days as-a-list don’t really bother me since maybe that makes semantic sense to the content of the calendar (assuming it has some)
  • But… seeing the titles of the days-of-the-week as the first items in the same list feels weird. Almost like that should be a separate list or something.
  • Or maybe it should all just be a <table> since it’s sort of tabular data (it stands to reason you might want to cross-reference and look at all Thursdays or whatever).

Anyway, the placement trickery is fun.

Here’s another (similar) approach from our collection of CSS Grid starter templates.

Direct Link to ArticlePermalink


The post A Calendar in Three Lines of CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

Responsive Grid Magazine Layout in Just 20 Lines of CSS

I was recently working on a modern take of the blogroll. The idea was to offer readers a selection of latest posts from those blogs in a magazine-style layout, instead of just popping a list of our favorite blogs in the sidebar.

The easy part was grabbing a list of posts with excerpts from our favorite RSS feeds. For that, we used a WordPress plugin, Feedzy lite, which can aggregate multiple feeds into a single time-ordered list — perfect for showcasing their latest offerings. The hard part was making it all look awesome.

The plugin’s default list UI is rather bland, so I wanted to style it to look like a newspaper or magazine website with a mixture of smaller and larger “featured content” panels.

This seems like an ideal case for CSS Grid! Create a grid layout for different layouts, say, one five-column layout and one three-column layout, then use media queries to switch between them at different break points. Right? But do we actually need those media queries — and all the hassle of identifying break points — when we can use grid’s auto-fit options to automatically create a fluid responsive grid for us? 

The approach sounded tempting, but when I started introducing column-spanning elements, I ran into trouble with the grid overflowing on narrow screens. Media queries appeared to be the only solution. That is, until I found a workaround!

After looking at several tutorials on CSS Grid, I found that they largely fall into two camps:

  1. Tutorials that show you how to create an interesting layout with spanned elements, but for a fixed number of columns.
  2. Tutorials that explain how to make a responsive grid that resizes automatically, but with all of the grid items the same width (i.e. without any spanned columns).

I want to make the grid do both: create a fully responsive fluid layout that includes responsively resizing multi-column elements as well.

The beauty is that once you understand the limitations of responsive grids, and why and when column spans break grid responsiveness, it is possible to define a responsive magazine/news style layout in just a dozen lines of code plus one simple media query (or even with no media queries if you are willing to limit your span options).

Here’s a visual showing the RSS plugin right out of the box and what it’ll look like after we style it up. 

(Demo)

This magazine-style grid layout is fully responsive with the colored featured panels adjusting dynamically as the number of columns change. The page displays around 50 posts, but the layout code is agnostic as to the number of items displayed. Ramp up the plugin to show 100 items and the layout stays interesting all the way down.

All of this is achieved using only CSS and with only a single media query to deal with a single column display on the narrowest of screens (i.e. smaller than 460px).

Incredibly, this layout only took 21 lines of CSS (excluding global content styling). However, to achieve such flexibility in such a few lines of code, I had to dig deep into the more obscure parts of some of  CSS Grid and learn how to work around some of its inherent limitations.

The essential elements of the code that produce this layout is incredibly short and a testament to the awesomeness of CSS Grid:

.archive {   display: grid;   grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));   grid-gap: 32px;   grid-auto-flow: dense; }  /* Extra-wide grid-posts */ .article:nth-child(31n + 1) {   grid-column: 1 / -1; } .article:nth-child(16n + 2) {   grid-column: -3 / -1; } .article:nth-child(16n + 10) {   grid-column: 1 / -2; }  /* Single column display for phones */ @media (max-width: 459px) {   .archive {     display: flex;     flex-direction: column;   } }

The techniques in this article could be used equally well to style any dynamically generated content such as the output from a latest posts widget, archive pages or search results.

Creating a responsive grid

I have set up seventeen items displaying a variety of mock content — headlines, images and excerpts — which are all contained in a wrapper

<div class="archive">   <article class="article">     <!-- content -->   </article>      <!-- 16 more articles -->    </div>

The code that turns these items into a responsive grid is remarkably compact:

.archive {   /* Define the element as a grid container */   display: grid;   /* Auto-fit as many items on a row as possible without going under 180px */   grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));   /* A little spacing between articles */   grid-gap: 1em; }

Notice how the heights of the rows automatically adjust to accommodate the tallest content in the row. If you change the width of the Pen, you will see the items grow and shrink fluidly and the number of columns change from one to five, respectively.

The CSS Grid magic at play here is the auto-fit keyword that works hand-in-hand with the minmax() function that’s applied to grid-template-columns.

How it works

We could have achieved the five-column layout alone using this:

.archive {   display: grid;   grid-template-columns: repeat(5, 1fr); }

However, this would create five columns that grow and shrink with different screen widths, but always stay at five columns, resulting in them becoming ridiculously narrow on small screens. The first thought might be to create a bunch of media queries and redefine the grid with different numbers of columns. That would work fine, but with the auto-fit keyword, it is all done automatically.

For auto-fit to work the way we want, we need to use the minmax() function. This tells the browser how small the columns can be squeezed down to followed by the maximum width they can expand to. Any smaller, and it will automatically reduce the number of columns. Any larger, and the number of columns increases.

.archive {   grid-template-columns: repeat (auto-fit, minmax(180px, 1fr)); }

In this example, the browser will fit in as many columns as it can 180px wide. If there is space left over the columns will all grow equally by sharing the remaining space between them —  that’s what the 1fr value is saying: make the columns equal fractions of the available width. 

Drag the window out and as the available space increases the columns all grow equally to use up any additional space. The columns will keep growing until the available space allows for an additional 180px column, at which point a whole new column appears. Decrease the screen width, and the process reverses, perfectly adjusting the grid all the way down to a single column layout. Magic!

And you get all this responsiveness out of just one line of code. How cool is that? 

Creating spans with “autoflow: dense”

So far, we have a responsive grid but all items the same width. For a news or magazine layout we need some content to be featured by spanning two or more columns or even, perhaps, to span all the columns.

To create multi-column spans we can add the column-span feature to the grid items we want to take up more space. For example, if we want the third item in our list to be two columns wide we can add:

.article:nth-child(3) {   grid-column: span 2; }

However, once we start adding spans a number of problems can arise. First, gaps may appear in the grid because a wide item may may not fit on the row, so grid auto-fit pushes it onto the next line, leaving a gap where it would have been:

The easy fix is adding grid-auto-flow: dense to the grid element which tells the browser to fill in any gaps with other items, effectively making the narrower content flow around the wider items like this:

Note that the items are now out of order, with the fourth item coming before the third item, which is double the width. There is no way round this as far as I can tell, and it is one of the limitations you have to accept with CSS Grid.

Check out Geoff Graham’s “The Auto-Flowing Powers of Grid’s Dense Keyword” for an introduction to grid-auto-flow: dense with examples of how it behaves.

Ways to specify spans

There are several ways to indicate how many columns an item should span. The easiest is to apply grid-columns: span [n] to one of the items, where n  is the number of columns the element will span. The third item in our layout has grid-column: span 2, which explains why it is double the width of other items that only span a single column.

Other methods require you to explicitly define grid lines. The numbering system for grid lines is as follows:

Grid lines can be specified from left-to-right using positive values (e.g. 1, 2, 3) or negative values (e.g. -1, -2, -3) to go from right-to-left. These can be used to place items on the grid using the grid-column property like this:

.grid-item {   grid-column: (start track) / (end track); }

So, this gives us additional ways to specify a spanned item. This is especially flexible as either the start or end value can be replaced with the span keyword. For example, the three-column blue box in the example above could be created by adding any of the following to the eighth grid item:

  • grid-column: 3 / 6
  • grid-column: -4 / -1
  • grid-column: 3 / span 3
  • grid-column: -4 / span 3
  • grid-column: span 3 / -1
  • Etc.

On a non-responsive (i.e. fixed columns) grid, these all produce the same effect (like the blue box above), however, if the grid is responsive and the number of columns changes, their differences start to become apparent. Certain column spans break the  layout with an auto-flowing grid, making the two techniques appear incompatible. Fortunately, there are some solutions which allow us to combine the two successfully. 

First, however, we need to understand the problem.

Overflow side-scrolling problems

Here are some featured areas created using the notation above:

(Demo)

It all looks good at full-width (five columns) but when resized to what should be two columns, the layout breaks like this:

 As you can see, our grid has lost its responsiveness and, although the container has shrunk, the grid is trying to maintain all five columns. To do so, it has given up trying to keep equal-width columns, and the grid is breaking out of the right-hand side of its container, causing horizontal scrolling.

Why is this? The problem comes about because the browser is trying to honor the explicit grid lines we named. At this width, the auto-fit grid should implicitly be displaying two columns, but our grid line numbering system contradicts this by explicitly referring to the fifth grid line. This contradiction leads to the mess. To display our implicit two-column grid correctly, the only line numbers allowed are 1, 2 and 3 and -3, -2, -1, like this:

But if any of our grid items contains grid-column references that lie outside this, such as grid line number 4, 5 or 6 (or -4, -5 or -6), the browser is getting mixed messages. On the one hand, we have asked it to automatic create flexible columns (which should implicitly give us two columns at this screen width) but we have also explicitly referred to grid lines that don’t appear in a two-column grid. When there is a conflict between implicit (automatic) columns and an implicit number of columns, grid always defers to the explicit grid; hence the unwanted columns and horizontal overflow (which has also been aptly named CSS data loss). Just like using grid line numbers, spans can also create explicit columns. So, grid-column: span 3 (the eighth grid item in the demo) forces the grid to explicitly adopt at least three columns, whereas we want it, implicitly display two.

At this point it might seem like the only way forward is to use media queries to change the grid-column values at the width where our layout breaks — but not so fast! That’s what I assumed at first. But after thinking it though a bit more and playing around with various options, I found there are a limited set of workarounds that work all the way down to two columns, leaving just one media query to cover a single column layout for the narrowest screens.

The solutions

The trick, I realized, is to only specify spans using grid lines that appear in the narrowest grid you intend to display. That is a two-column grid in this case. (We will use a media query to cover the single column scenario for very narrow screens.) That means we can safely use grid lines 1, 2 and 3 (or -3, -2 and -1) without breaking the grid.

I initially thought that meant limiting myself to a maximum span of two columns, using combinations of the following:

  • grid column: span 2
  • grid-column: 1 /3
  • grid-column: -3 / -1

Which remains perfectly responsive right down to two columns:

Although this works, it is rather limiting from a design perspective, and not particularly exciting. I wanted to be able to create spans that would be three, four or even five columns wide on large screens. But how? My first thought was that I would have to resort to media queries (OMG old habits die hard!) but I was trying to get away from that approach and think differently about responsive design.

Taking another look at what we can do with just 1 to 3 and -3 to -1, I gradually realized that I could mix positive and negative line numbers for the grid column’s start and end values ,such as 1/-3 and 2/-2. At first glance, this does not seem very interesting. That changes when you realize where these lines are located as you resize the grid: these spanned elements change width with the screen size. This opened up a whole new set of possibilities for responsive column spans: items that will span different numbers of columns as the screen gets wider, without needing media queries.

The first example I discovered is grid-column: 1/-1.This makes the item act like a full-width banner, spanning from the first to the last column at all column numbers. it even works down to one column wide!

By using grid-column: 1/-2, a left-aligned nearly-full-width span could be created that would always leave a one column item to the right of it. When shrunk to two columns it would shrink responsively to a single column. Surprisingly, it even works when shrunk to a single column layout. (The reason seems to be that grid will not collapse an item to zero width, so it remains one column wide, as does grid-column: 1/1.) I assumed grid-column: 2/-1 would work similarly, but aligned with the right-hand edge, and for the most part it does, except at one column display when it causes overflow.

Next I tried 1/-3  which worked fine on wider screen, showing at least three columns, and smaller screens, showing one column. I thought it would do something weird on a two-column grid as the first grid line is the same as the grid line with -3. To my surprise, it still displays fine as a single-column item. 

After a lot of playing around, I came up with eleven possible grid column values using grid line numbers from the two-column grid. Surprisingly, three of these work right down to single-column layouts. Seven more work down to two columns and would only need a single media query to deal with single column display.

Here is the full list:

Responsive grid-column values, showing how they display at different screen sizes in an auto-fit grid. (Demo)

As you can see, although this is a limited subset of every possible responsive span, there are actually a lot of possibilities.

  • 2/-2 is interesting as it creates a centered span which works all the way down to one column! 
  • 3/-1 is  least useful as it causes overflow even with two-columns.
  • 3/-3 was a surprise.

By using a variety of grid-column values from this list, it is possible to create an interesting and fully responsive layout. Using a single media query for the narrowest single-column display, we have ten different grid-column span patterns to play with.  

The single-column media query is generally straightforward as well. The one on this final demo reverts to using flexbox at smaller screens:

@media (max-width: 680px) {   .archive {     display: flex;     flex-direction: column;   }    .article {     margin-bottom: 2em;   } }

Here is the final grid which, as you can see, is fully responsive from one to five columns:

(Demo)

Using :nth-child() to repeat variable length displays

The last trick I used to get my code down to two dozen lines was the :nth-child(n) selector which I used to style multiple items in my grid. I wanted my span styling to apply to multiple items in my feed, so that the featured post boxes appeared regularly throughout the page. To start with I used a comma-separated selector list, like this:

.article:nth-child(2), .article:nth-child(18), .article:nth-child(34), .article:nth-child(50)  {   background-color: rgba(128,0,64,0.8);   grid-column: -3 / -1; }

But I soon found this cumbersome, especially as I had to repeat this list for each child element I wanted to style within each article — such as the title, links and so on. During prototyping, if I wanted to play around with the position of my spanned elements, I had to manually change the numbers in each of these lists, which was tedious and error prone.

That’s when I realized that I could use a powerful feature :nth-child pseudo-selector instead of a simple integer as I had used in the list above. :nth-child(n) can also take an equation, such as :nth-child(2n+ 2), which will target every second child element.

Here is how I used the :nth-child([formula]) to create the blue full-width panels in my grid which appear at the very top of the page, and is repeated just over half way down:

.article:nth-child(31n + 1) {   grid-column: 1 / -1;   background: rgba(11, 111, 222, 0.5); }

The bit in the brackets (31n + 1 ) ensures that the 1st, 32nd, 63rd, etc. child is selected. The browser runs a loop starting with n=0 (in which case 31 * 0 + 1 = 1), then n=1 (31 * 1 + 1 = 32), then n=2 (31 * 2 + 1 = 63). In the last case, the browser realizes that  there is no 63rd child item so it ignores that, stops looping, and applies the CSS to the 1st and 32nd children.

I do something similar for the purple boxes which alternate down the page from right-to-left:

.article:nth-child(16n + 2) {   grid-column: -3 / -1;   background: rgba(128, 0, 64, 0.8); }  .article:nth-child(16n + 10) {   grid-column: 1 / -2;   background: rgba(128, 0, 64, 0.8); }

The first selector is for the right-hand purple boxes. The 16n + 2 makes sure that the styling applies to every 16th grid item, starting with the second item.

The second selector targets the right-hand boxes. It uses the same spacing (16n) but with a different offset (10). As a result, these boxes appear regularly on the right-hand side for grid items 10, 26, 42, etc.

When it comes to the visual styling for these grid items and their contents, I used another trick to reduce repetition. For styles that both boxes share (such as the background-color, for example) a single selector can be used to target both:

.article:nth-child(8n + 2) {   background: rgba(128, 0, 64, 0.8);   /* Other shared syling */ }

This will target items 2, 10, 18, 26, 34, 42, 50, and so forth.  In other words,  it selects both the left- and right-hand featured boxes.

It works because 8n is exactly half of 16n, and because the offsets used in the two separate selectors have a difference of 8 (i.e. the difference between +10 and +2 is 8) 

Final thoughts

Right now, CSS Grid can be used to create flexible responsive grids with minimal code, but this does come with some significant limitations on positioning elements without the retrograde step of using media queries.

It would be great to be able to specify spans that would not force overflow on smaller screens. At the moment, we effectively tell the browser, “Make a responsive grid, please,” which it does beautifully. But when we continue by saying, “Oh, and make this grid item span four columns,” it throws a hissy-fit on narrow screens, prioritizing the four-column span request rather than the responsive grid. It would be great to be able to tell grid to prioritize responsiveness over our span request. Something like this:

.article {   grid-column: span 3, autofit; }

Another issue with responsive grids is the last row. As the screen width changes the last row will frequently not be filled. I spent a long time looking for a way to make the last grid item span (and hence fill) the remaining columns, but it seems you can’t do it in Grid right now. It would be nice if we could specify the item’s start position with a keyword like auto meaning, “Please leave the left-hand edge wherever it falls.” Like this:

.article {   grid-column: auto, -1; }

…which would make the left-hand edge span to the end of the row.

The post Responsive Grid Magazine Layout in Just 20 Lines of CSS appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

A Trick That Makes Drawing SVG Lines Way Easier

When drawing lines with SVG, you often have a <path> element with a stroke. You set a stroke-dasharray that is as long as the path itself, as well as a stroke-offset that extends so far that you that it’s initially hidden. Then you animate the stroke-offset back to 0 so you can watch it “draw” the shape.

Figuring out the length of the path is the trick, which fortunately you can do in JavaScript by selecting the path and doing pathEl.getTotalLength(). It’ll probably be some weird decimal. A smidge unfortunate we can’t get that in CSS, but c’est la vie.

Here’s the trick!

You don’t have to measure the length of the path, because you can set it.

So you do like:

<path d="M66.039,133.545 ... " pathLength="1" />

That doesn’t do anything by itself (as far as I know). It’s not like that only draws part of the path — it still draws the whole thing like as if you did nothing, only now the “math” of the path length is based on a value of 1.

Now we can set the stroke-dasharray to 1, and animate the offset in CSS!

.path {   stroke-dasharray: 1;   stroke-dashoffset: 1;   animation: dash 5s linear alternate infinite; }  @keyframes dash {   from {     stroke-dashoffset: 1;   }   to {     stroke-dashoffset: 0;   } }

Which works:

See the Pen
Basic Example of SVG Line Drawing, Backward and Forward
by Chris Coyier (@chriscoyier)
on CodePen.

High five to Adam Haskell who emailed me about this a few months back.


Hey, speaking of SVG line drawing: Lemonade made a landing page for their 2019 charity that uses scroll-triggered SVG line drawing up and down the entire page. They did a behind-the-scenes look at it, which I always appreciate.

animated GIF of line drawing on Lemonade page - as page scrolls down a teddy bear shape is drawn

The post A Trick That Makes Drawing SVG Lines Way Easier appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements

I recently had to craft a newspaper-like design that featured multiple row and column spans with divider lines in between them. Take a look at the mockup graphic here and see if it makes you sweat at all. If you’re like me, you have been around a while and know just how difficult this would have been with old layout techniques.

Newspaper design with line dividers between cells

The project came with a few requirements:

  • Show the outlines of the grid
  • Columns can be wider, or longer than others
  • Divider lines must be shown between the various blocks

CSS Grid: Teaching an old layout new tricks

Newspaper layouts can cause headaches because everyday CSS is one-dimensional, meaning that elements flow on either a horizontal or vertical axis. Even modern flexbox layout is still uni-directional.

For a layout like this, we would almost want the properties that good ol’ HTML tables once provided: things like row and column spans to stretch cells in all directions. We would also want the benefits of modern day CSS, with all the responsiveness and flexible boxes that can grow to fill available space.

CSS grid combines the best of tables with the best of flexible boxes. In fact, grid’s even better because it provides the grid-gap property for creating gutters between cells while taking available space into account. Powerful as this may be, how can we create divider-lines exactly in the middle of those gutters?

Let’s look at three techniques to make that happen.

What we’ll create

First, we will build a simplified version of the newspaper design that’ll help illustrate the crux of the three different techniques that we’re going to cover. A deceptively easy design, one would say.

Column and row spans in a CSS grid layout

Technique 1: The faux column

This solution creates “faux” columns that allow us to draw vertical lines, and then place a grid on top. Horizontal dividers are painted if needed. The “faux” columns are created by using pseudo selectors in the grid container.

<div class="frontpage">   <div class="fp-cell fp-cell--1">     <div class="fp-item">1</div>   </div>   <div class="fp-cell fp-cell--2">     <div class="fp-item">2</div>   </div>   <div class="fp-cell fp-cell--3 fp-cell--border-top">     <div class="fp-item">3</div>   </div>   <div class="fp-cell fp-cell--4 fp-cell--border-top">     <div class="fp-item">4</div>   </div> </div>

See the Pen
Newspaper-design, ‘faux-column’ technique
by Marco Troost (@marco-troost)
on CodePen.

Setting up the lines between the columns

Let’s create a three-column container using display: grid and pseudo-selectors (:before and :after) to create two columns that fill 100% of the container’s height.

.frontpage {   position: relative;   display: grid;   /* Three columns */   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  /* Two faux columns */ .frontpage:before, .frontpage:after {   position: absolute;   top: 0;   height: 100%;   content: '';   width: calc(33.3% - 4px); }  .frontpage:before {   left: 0;   border-right: 1px solid #DADCE0; }  .frontpage:after {   right: 0;   border-left: 1px solid #DADCE0; }

Note: 33% of the container doesn’t take the gutter width into account, so you’ll have to compensate accordingly.

This is calculated as:

33% minus (gutter-width divided by (amount of gutters times amount of gutters)) divided by amount of gutters)

Or, with actual numbers:

33% - (32 / (2* 2)) / 2 = 4

We could use one pseudo-selector instead:

.frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  .frontpage:before {   box-sizing: border-box;   position: absolute;   top: 0;   height: 100%;   content: '';   left: calc(33.3% - 5.3px);   width: calc(33.3% + 10.7px);   border-left: 1px solid #DADCE0;   border-right: 1px solid #DADCE0; }

See the Pen
Newsgrid-layout ‘faux-columns’ (using only :before)
by Marco Troost (@marco-troost)
on CodePen.

Note: A different calculation is needed when using only one pseudo-selector: One for positioning, and one for width.

The width is calculated as:

33% plus (amount of gutters times gutter-width) / (amount of gutters times amount of columns)

Again, with actual numbers:

33% + (2 * 32) / (2 * 3) = 10.7

The position is calculated as:

33% minus (amount of gutters times gutter-width) / (amount of gutters times amount of columns) divided by 2)

Making the grid

The design consists of four blocks of content. We’re going to place them in the container and give them a modifier class for future reference while making sure their z-index is higher than the pseudo-selectors of the grid.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3"></div>   <div class="fp-cell fp-cell--4"></div> </div>

Now let’s set the background color for the cells (.fp-cell) to white. This way, the vertical lines won’t show through. We can also set the vertical padding for the cell to 16px in order to match half of the gutter.

The first and second content blocks should get their own unique spans as shown in the design. The first block spans all the way down and the second block spans the second and third columns.

.fp-cell {   position: relative;   z-index: 2;   padding: 16px 0;   background-color: #fff; }  /* Span all the way down! */ .fp-cell--1 {   grid-row: 1 / span 2; }  /* Span the second and third columns */ .fp-cell--2 {   grid-column: 2 / span 2; }

Vertical line dividers

If you look at the design, only the last two cells need a horizontal border. We can give ’em a sweet modifier class.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3 fp-cell--border-top"></div>   <div class="fp-cell fp-cell--4 fp-cell--border-top"></div> </div>
.fp-cell--border-top:before {   content: '';   position: absolute;   top: 0;   left: -16px;   right: -16px;   border-top: 1px solid #DADCE0; }

The negative margins are half of the gutter width.

Technique #2: Using background-color

Another way to create the dividers is to utilize the grid-gap property. This solution doesn’t necessarily create a “real” distance between cells, but rather leaves some blank space where the background-color of the grid can shine through. The gutter width is delegated to padding within the grid cells.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">       <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   overflow-x: hidden;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   margin: 0 -16px;   background-color: #DADCE0; }  .fp-cell {   background-color: #fff;   padding: 16px; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, background-color technique
by Marco Troost (@marco-troost)
on CodePen.

Since all cells have an extra 16px of horizontal padding, the grid needs to be offset by just as much. A wrapper container will take care of the overflow.

<div class="container">   <div class="frontpage">   <!-- ... -->   </div> </div>
.container {   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   background-color: #DADCE0;   margin: 0 -16px; }

Technique #3: Creating a cell border

This solution appends a right and bottom border to each cell. Like the last example, the grid-gap is mimicked by adding padding to the cell content. That means it also needs to be wrapped in an extra container.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">         <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   border-top: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }  .fp-cell {   padding: 16px;   background-color: #fff;   border-right: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, ‘cell-border’-technique
by Marco Troost (@marco-troost)
on CodePen.

As mentioned, each cell is given a border on the right and on the bottom. The main trick here is the use of the (asymmetrical) negative margin on the grid. This is needed to compensate for the cell’s right border.

.frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }

Conclusion

Occam’s razor stipulates that the simplest solution wins. In our case, that’s technique number two. But then again, the other solutions have plenty of merit and they could prove useful if, for example, access to the DOM is not possible.

All of these techniques will work. Choosing the right one depends on your use case. The first technique uses the actual grid-gap property to create the gaps, but the others are perhaps easier to understand at a glance… and perhaps easier to maintain as well.

The post Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

Build a Chat App Using React Hooks in 100 Lines of Code

We’ve looked at React Hooks before, around here at CSS-Tricks. I have an article that introduces them as well that illustrates how to use them to create components through functions. Both articles are good high-level overviews about the way they work, but they open up a lot of possibilities, too.

So, that’s what we’re going to do in this article. We’re going to see how hooks make our development process easier and faster by building a chat application.

Specifically, we are building a chat application using Create React App. While doing so, we will be using a selection of React Hooks to simplify the development process and to remove a lot of boilerplate code that’s unnecessary for the work.

There are several open source Reacts hooks available and we’ll be putting those to use as well. These hooks can be directly consumed to build features that otherwise would have taken more of code to create. They also generally follow well-recognized standards for any functionality. In effect, this increases the efficiency of writing code and provides secure functionalities.

Let’s look at the requirements

The chat application we are going to build will have the following features:

  • Get a list of past messages sent from the server
  • Connect to a room for group chatting
  • Get updates when people disconnect from or connect to a room
  • Send and receive messages

We’re working with a few assumptions as we dive in:

  • We’ll consider the server we are going to use as a blackbox. Don’t worry about it working perfectly as we’re going to communicate with it using simple sockets.
  • All the styles are contained in a single CSS file, can be copied to the src directory. All the styles used within the app are linked in the repository.

Getting set up for work

OK, we’re going to want to get our development environment ready to start writing code. First off, React requires both Node and npm. You can set them up here.

Let’s spin up a new project from the Terminal:

npx create-react-app socket-client cd socket-client npm start

Now we should be able to navigate to http://localhost:3000 in the browser and get the default welcome page for the project.

From here, we’re going to break the work down by the hooks we’re using. This should help us understand the hooks as we put them into practical use.

Using the setState hook

The first hook we’re going to use is useState. It allows us to maintain state within our component as opposed to, say, having to write and initialize a class using this.state. Data that remains constant, such as username, is stored in useState variables. This ensures the data remains easily available while requiring a lot less code to write.

The main advantage of useState is that it’s automatically reflected in the rendered component whenever we update the state of the app. If we were to use regular variables, they wouldn’t be considered as the state of the component and would have to be passed as props to re-render the component. So, again, we’re cutting out a lot of work and streamlining things in the process.

The hook is built right into React, so we can import it with a single line:

import React, { useState } from 'react';

We are going to create a simple component that returns “Hello” if the user is already logged in or a login form if the user is logged out. We check the id variable for that.

Our form submissions will be handled by a function we’re creating called handleSubmit. It will check if the Name form field is completed. If it is, we will set the id and room values for that user. Otherwise, we’ll throw in a message reminding the user that the Name field is required in order to proceed.

// App.js  import React, { useState } from 'react'; import './index.css';  export default () => {   const [room, setRoom] = useState('');   const [id, setId] = useState('');    const handleSubmit = e => {     e.preventDefault();     const name = document.querySelector('#name').value.trim();     const room_value = document.querySelector('#room').value.trim();     if (!name) {       return alert("Name can't be empty");     }     setId(name);     setRoom(document.querySelector('#room').value.trim());   };    return id !== '' ? (     <div>Hello</div>   ) : (     <div style={{ textAlign: 'center', margin: '30vh auto', width: '70%' }}>       <form onSubmit={event => handleSubmit(event)}>         <input id="name" required placeholder="What is your name .." /><br />         <input id="room" placeholder="What is your room .." /><br />         <button type="submit">Submit</button>       </form>     </div>   ); };

That’s how we’re using the useState hook in our chat application. Again, we’re importing the hook from React, constructing values for the user’s ID and chat room location, setting those values if the user’s state is logged in, and returning a login form if the user is logged out.

Using the useSocket hook

We’re going to use an open source hook called useSocket to maintain a connection to our server. Unlike useState, this hook is not baked into React, so we’re going to have to add it to our project before importing it into the app.

npm add use-socket.io-client

The server connection is maintained by using the React Hooks version of the socket.io library, which is an easier way of maintaining websocket connections with a server. We are using it for sending and receiving real-time messages as well as maintaining events, like connecting to a room.

The default socket.io client library has global declarations, i.e., the socket variable we define can be used by any component. However, our data can be manipulated from anywhere and we won’t know where those changes are happening. Socket hooks counter this by constraining hook definitions at the component level, meaning each component is responsible for its own data transfer.

The basic usage for useSocket looks like this:

const [socket] = useSocket('socket-url')

We’re going to be using a few socket APIs as we move ahead. For the sake of reference, all of them are outlined in the socket.io documentation. But for now, let’s import the hook since we’ve already installed it.

import useSocket from 'use-socket.io-client';

Next, we’ve got to initialize the hook by connecting to our server. Then we’ll log the socket in the console to check if it is properly connected.

const [id, setId] = useState(''); const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');  socket.connect(); console.log(socket);

Open the browser console and the URL in that snippet should be logged.

Using the useImmer hook

Our chat app will make use of the useImmer hook to manage state of arrays and objects without mutating the original state. It combines useState and Immer to give immutable state management. This will be handy for managing lists of people who are online and messages that need to be displayed.

Using Immer with useState allows us to change an array or object by creating a new state from the current state while preventing mutations directly on the current state. This offers us more safety as far as leaving the current state intact while being able to manipulate state based on different conditions.

Again, we’re working with a hook that’s not built into React, so let’s import it into the project:

npm add use-immer

The basic usage is pretty straightforward. The first value in the constructor is the current state and the second value is the function that updates that state. The useImmer hook then takes the starting values for the current state.

const [data, setData] = useImmer(default_value)

Using the setData hook

Notice the setData hook in that last example? We’re using that to make a draft copy of the current data we can use to manipulate the data safely and use it as the next state when changes become immutable. Thus, our original data is preserved until we’re done running our functions and we’re absolutely clear to update the current data.

setData(draftState => {    draftState.operation();  });  // ...or  setData(draft => newState);  // Here, draftState is a copy of the current data

Using the useEffect hook

Alright, we’re back to a hook that’s built right into React. We’re going to use the useEffect hook to run a piece of code only when the application loads. This ensures that our code only runs once rather than every time the component re-renders with new data, which is good for performance.

All we need to do to start using the hook is to import it — no installation needed!

import React, { useState, useEffect } from 'react';

We will need a component that renders a message or an update based on the presence or absence of a sende ID in the array. Being the creative people we are, let’s call that component Messages.

const Messages = props => props.data.map(m => m[0] !== '' ?  (<li key={m[0]}><strong>{m[0]}</strong> : <div className="innermsg">{m[1]}</div></li>)  : (<li key={m[1]} className="update">{m[1]}</li>) );

Let’s put our socket logic inside useEffect so that we don’t duplicate the same set of messages repeatedly when a component re-renders. We will define our message hook in the component, connect to the socket, then set up listeners for new messages and updates in the useEffect hook itself. We will also set up update functions inside the listeners.

const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');       socket.connect();  const [messages, setMessages] = useImmer([]); useEffect(()=>{   socket.on('update', message => setMessages(draft => {     draft.push(['', message]);   }));    socket.on('message que',(nick, message) => {     setMessages(draft => {       draft.push([nick, message])     })   }); },0);

Another touch we’ll throw in for good measure is a “join” message if the username and room name are correct. This triggers the rest of the event listeners and we can receive past messages sent in that room along with any updates required.

// ...   setRoom(document.querySelector('#room').value.trim());   socket.emit('join', name, room); };  return id ? (   <section style={{display:'flex',flexDirection:'row'}} >     <ul id="messages"><Messages data={messages}></Messages></ul>     <ul id="online"> &#x1f310; :</ul>     <div id="sendform">       <form id="messageform" style={{display: 'flex'}}>         <input id="m" /><button type="submit">Send Message</button>       </form>     </div>   </section> ) : ( // ...

The finishing touches

We only have a few more tweaks to wrap up our chat app. Specifically, we still need:

  • A component to display people who are online
  • A useImmer hook for it with a socket listener
  • A message submission handler with appropriate sockets

All of this builds off of what we’ve already covered so far. I’m going to drop in the full code for the App.js file to show how everything fits together.

// App.js  import React, { useState, useEffect } from 'react';  import useSocket from 'use-socket.io-client';  import { useImmer } from 'use-immer';  import './index.css';  const Messages = props => props.data.map(m => m[0] !== '' ? (<li><strong>{m[0]}</strong> : <div className="innermsg">{m[1]}</div></li>) : (<li className="update">{m[1]}</li>) );  const Online = props => props.data.map(m => <li id={m[0]}>{m[1]}</li>);  export default () => {    const [room, setRoom] = useState('');    const [id, setId] = useState('');      const [socket] = useSocket('<https://open-chat-naostsaecf.now.sh>');   socket.connect();    const [messages, setMessages] = useImmer([]);      const [online, setOnline] = useImmer([]);      useEffect(()=>{     socket.on('message que',(nick,message) => {       setMessages(draft => {         draft.push([nick,message])       })     });        socket.on('update',message => setMessages(draft => {       draft.push(['',message]);     }))        socket.on('people-list',people => {       let newState = [];       for(let person in people){         newState.push([people[person].id,people[person].nick]);       }       setOnline(draft=>{draft.push(...newState)});       console.log(online)     });        socket.on('add-person',(nick,id)=>{       setOnline(draft => {         draft.push([id,nick])       })     })        socket.on('remove-person',id=>{       setOnline(draft => draft.filter(m => m[0] !== id))     })        socket.on('chat message',(nick,message)=>{       setMessages(draft => {draft.push([nick,message])})     })   },0);      const handleSubmit = e => {     e.preventDefault();     const name = document.querySelector('#name').value.trim();       const room_value = document.querySelector('#room').value.trim();     if (!name) {       return alert("Name can't be empty");     }     setId(name);     setRoom(document.querySelector('#room').value.trim());     console.log(room)     socket.emit("join", name,room_value);   };      const handleSend = e => {     e.preventDefault();     const input = document.querySelector('#m');     if(input.value.trim() !== ''){       socket.emit('chat message',input.value,room);       input.value = '';     }   }      return id ? (     <section style={{display:'flex',flexDirection:'row'}} >       <ul id="messages"><Messages data={messages} /></ul>       <ul id="online"> &#x1f310; : <Online data={online} /> </ul>       <div id="sendform">         <form onSubmit={e => handleSend(e)} style={{display: 'flex'}}>             <input id="m" /><button style={{width:'75px'}} type="submit">Send</button>         </form>       </div>     </section>   ) : (     <div style={{ textAlign: 'center', margin: '30vh auto', width: '70%' }}>       <form onSubmit={event => handleSubmit(event)}>         <input id="name" required placeholder="What is your name .." /><br />         <input id="room" placeholder="What is your room .." /><br />         <button type="submit">Submit</button>       </form>     </div>   ); };

Wrapping up

That’s it! We built a fully functional group chat application together! How cool is that? The complete code for the project can be found here on GitHub.

What we’ve covered in this article is merely a glimpse of how React Hooks can boost your productivity and help you build powerful applications with powerful front-end tooling. I have built a more robust chat application in this comprehensive tutorial. Follow along if you want to level up further with React Hooks.

Now that you have hands-on experience with React Hooks, use your newly gained knowledge to get even more practice! Here are a few ideas of what you can build from here:

  • A blogging platform
  • Your own version of Instagram
  • A clone of Reddit

Have questions along the way? Leave a comment and let’s make awesome things together.

The post Build a Chat App Using React Hooks in 100 Lines of Code appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]