How to Make a List Component with Emotion
While doing code refactoring at Sentry this week, I found that we were missing a common list component that could be common between projects and features. So I started to create one, but the problem is: we use Emotion for style in Sentry, and I only have a preliminary understanding of Emotion, which is described in its documentation as...
…A library for writing CSS styles using JavaScript. In addition to providing a powerful, predictable style combination, it offers an excellent developer experience with features including source mapping, tagging, and testing utilities. String and object styles are supported.
If you've never heard of Emotion, the basic idea is as follows: When we work on a large code base with many components, we want to make sure we can control the cascading stylesheets of CSS. So, suppose you have a .active
class in one file and you want to make sure that it does not affect the style of a completely standalone component that also has a .active
class in another file.
Emotion solves this problem by adding custom strings to your class names so they don't conflict with other components. Here is an example of HTML that it may output:
<div></div>
Very concise, right? However, there are many other tools and workflows that can implement very similar features, such as CSS Modules.
To start creating components, we first need to install Emotion into our project. I won't go into details as it depends on your environment and settings. However, once it is done, we can create a new component like this:
import React from 'react'; import styled from '@emotion/styled'; export const List = styled('ul')` list-style: none; padding: 0; `;
This looks weird to me because we are not only doing<ul></ul>
The element is written in style, and the component should also render a<ul></ul>
element. Combining markers and styles at the same time in one place feels weird, but I do like the simplicity of it. It just kind of disrupts my mind model and the separation of concerns between HTML, CSS and JavaScript. In another component we can import this<list></list>
And use it like this:
import List from 'components/list'; <list>This is a list item.</list>
The styles we add to the list component will then be converted to the class name (e.g. .oefioaueg
) and then added to the one we define in the component<ul></ul>
in the element. But we are not done yet! For list design I need to be able to render with the same component<ul></ul>
and<ol></ol>
. I also need a version that allows me to place icons in each list item. Like this: The cool (and a little weird) thing about Emotion is that we can use as
attribute to select the HTML element to render when importing the component. We can use this property to create our<ol></ol>
Variants without creating custom type attributes or other content. And this looks like this:
<list> This will present an ul.</list> <list as="ol">This will present an ol.</list>
Not only is this weird to me, right? However, this is very clever because it means we don't have to do any weird logic in the component itself to change the tag.
At this point, I began to note what the ideal API for this component might look like, because then we can go back from there. This is what I imagined:
<list> <listitem>Item 1</listitem> <listitem>Project 2</listitem> <listitem>Project 3</listitem> </list> <list> <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }> Item 1 <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }>Project 2 <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }>Project 3 </list> <list as="ol"> <listitem>Item 1</listitem> <listitem>Project 2</listitem> <listitem>Project 3</listitem> </list>
So after making this sketch I know we need two components, as well as being able to<listitem></listitem>
The ability to nest icon subcomponents in it. We can start like this:
import React from 'react'; import styled from '@emotion/styled'; export const List = styled('ul')` list-style: none; padding: 0; margin-bottom: 20px; ol& { counter-reset: numberedList; } `;
This special ol&
syntax is what we tell Emotion that these styles are only rendered in the element as<ol></ol>
Applicable method only. It is usually best to add background: red;
to this element to make sure your component renders the content correctly. Next is our subcomponent<listitem></listitem>
. It should be noted that in Sentry we also use TypeScript, so we are defining our<listitem></listitem>
Before component, we need to set our props first:
type ListItemProps = { icon?: React.ReactNode; children?: string | React.ReactNode; className?: string; };
Now we can add ours<iconwrapper></iconwrapper>
component, it will be<listitem></listitem>
Adjustment<icon></icon>
The size of the component. If you remember the example above, I want it to look like this:
<list> <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }> Item 1 <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }>Project 2 <listitem color="orange400" icon="{<IconBusiness" size="sm"></listitem> }>Project 3 </list>
The IconBusiness
component is a pre-existing component that we want to wrap in<span></span>
so that we can style it. Thankfully, we only need a little CSS to align the icons correctly with the text, and<iconwrapper></iconwrapper>
All of this can be handled for us:
type ListItemProps = { icon?: React.ReactNode; children?: string | React.ReactNode; className?: string; }; const IconWrapper = styled('span')` display: flex; margin-right: 15px; height: 16px; align-items: center; `;
After doing this we can finally add ours below these two components<listitem></listitem>
Components, although it is much more complex. We need to add props, and then when icon
prop exists, we can render the above<iconwrapper></iconwrapper>
, and render the icon
component passed into it. I also added all the styles below so you can see how I style each of these variations:
export const ListItem = styled(({ icon, className, children }: ListItemProps) => (
- */
ol & {
&:before {
counter-increment: numberedList;
content: counter(numberedList);
top: 3px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 18px;
height: 18px;
font-size: 10px;
font-weight: 600;
border: 1px solid #aaa;
border-radius: 50%;
background-color: transparent;
margin-right: 20px;
}
}
`;
That's it! A relatively simple build using Emotion<list></list>
Components. However, after completing this exercise, I'm still not sure if I like this grammar. I think it makes simple things very simple, but medium-sized components are much more complex than they should be. Also, it can be very confusing for newbies, which makes me a little worried.
But I think everything is learning experience. Anyway, I'm glad to have the opportunity to deal with this little component, as it taught me some knowledge about TypeScript, React, and how to make our styles readable to some extent.
The above is the detailed content of How to Make a List Component with Emotion. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

No matter what stage you’re at as a developer, the tasks we complete—whether big or small—make a huge impact in our personal and professional growth.

It's out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That's like this.

I'd say "website" fits better than "mobile app" but I like this framing from Max Lynch:

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.
