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!

I recently found a solution to dynamically update the color of any product image. So with just one of a product, we can colorize it in different ways to show

In this week's roundup, Lighthouse sheds light on third-party scripts, insecure resources will get blocked on secure sites, and many country connection speeds

There are loads of analytics platforms to help you track visitor and usage data on your sites. Perhaps most notably Google Analytics, which is widely used

The document head might not be the most glamorous part of a website, but what goes into it is arguably just as important to the success of your website as its

What's happening when you see some JavaScript that calls super()?.In a child class, you use super() to call its parent’s constructor and super. to access its

JavaScript has a variety of built-in popup APIs that display special UI for user interaction. Famously:

I was chatting with some front-end folks the other day about why so many companies struggle at making accessible websites. Why are accessible websites so hard

There is an HTML attribute that does exactly what you think it should do:


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

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 English version
Recommended: Win version, supports code prompts!

SublimeText3 Linux new version
SublimeText3 Linux latest version