Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

markzzw
markzzw

Posted on

     

Use tailwind within atomic design methodology

original:https://markzzw.gitbook.io/zewei-zhangs-minds/core-mind/use-tailwind-in-atomic-design-methodology

Tailwind CSS has gradually become the preferred style processing solution in front-end development. Its simple integration and flexible configurability make it gradually occupy a higher position in front-end development. However, with the use of Tailwind CSS, many front-end developers have also experienced discomfort. Too many classnames cause the code to look untidy, and in the case of complex styles, writing Tailwind CSS is very complicated, which is not conducive to maintenance, so can the above problems be solved by following the theory of atomic components when using Tailwind CSS?

Atomic Component

Atomic design

Before discussing how to combine atomic components and Tailwind CSS, let's take a look at the atomic component methodology, which divides pages into the following five levels.

  1. Atoms

    For the definition of the atom as the smallest non-divisible component in the design system, then we should split the web page should be the corresponding html native tag with the corresponding style, that is, input/h1/button and other components, such components can not be split again, and can be used independently.

  2. Molecules

    A molecule is defined as a component of the design system composed of atomic components, such as a search box with a search button, avatar, card, etc

  3. Organisms

    An organization is defined as a component composed of atoms and molecules in the design system. Such components generally have certain business capabilities, such as tab components, datepicker components, and list components

  4. Templates

    The template is defined as a high-reuse interface without data composed of atoms, molecules, and organizations in the design system, such as the table page of the background management system, which has high reuse.

  5. Pages

    The definition of the page is that after the template is filled with data, the real page is displayed, also known as a high-fidelity page.

The periodic table of HTML elements by Josh Duck.

Each level is pieced together from the previous levels to form the final page. In this methodology, the main thing is to find atomic components. The following figure helps us to label the atomic components well (native Html elements).

Atomic Component fit with Tailwind CSS

The page is made up of basic components. The atomic component methodology is not to split the page components as small as possible, but to form molecular components through atomic components and organize components, and then build pages through page templates, which is a process from small to large.

In the development methodology of atomic components, we need to clearly identify which Atomic components are, and then modify the atomic components. Tailwind CSS is just the methodology of Atomic CSS, turning the miscellaneous css styles into a single css attribute.

This solves the problem of hard-to-read html code with a lot of classnames in the code, which is to wrap atomic components and then use atomic components to compose molecular components.

This code is an example of the official website, we will use this example to refactor to show how to do the atomic component.

Tailwind demo

functionShoppingCard(){return<divclassName="flex font-sans"><divclassName="flex-none w-48 relative"><imgsrc="/classNameic-utility-jacket.jpg"alt=""className="absolute inset-0 w-full h-full object-cover"loading="lazy"/></div><formclassName="flex-auto p-6"><divclassName="flex flex-wrap"><h1className="flex-auto text-lg font-semibold text-slate-900">                    Utility Jacket</h1><divclassName="text-lg font-semibold text-slate-500">                    $110.00</div><divclassName="w-full flex-none text-sm font-medium text-slate-700 mt-2">                    In stock</div></div><divclassName="flex items-baseline mt-4 mb-6 pb-6 border-b border-slate-200"><divclassName="space-x-2 flex text-sm"><label><inputclassName="sr-only peer"name="size"type="radio"value="xs"checked/><divclassName="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">                            XS</div></label><label><inputclassName="sr-only peer"name="size"type="radio"value="s"/><divclassName="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">                            S</div></label><label><inputclassName="sr-only peer"name="size"type="radio"value="m"/><divclassName="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">                            M</div></label><label><inputclassName="sr-only peer"name="size"type="radio"value="l"/><divclassName="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">                            L</div></label><label><inputclassName="sr-only peer"name="size"type="radio"value="xl"/><divclassName="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">                            XL</div></label></div></div><divclassName="flex space-x-4 mb-6 text-sm font-medium"><divclassName="flex-auto flex space-x-4"><buttonclassName="h-10 px-6 font-semibold rounded-md bg-black text-white"type="submit">                        Buy now</button><buttonclassName="h-10 px-6 font-semibold rounded-md border border-slate-200 text-slate-900"type="button">                        Add to bag</button></div><buttonclassName="flex-none flex items-center justify-center w-9 h-9 rounded-md text-slate-300 border border-slate-200"type="button"aria-label="Like"><svgwidth="20"height="20"fill="currentColor"aria-hidden="true"><pathfill-rule="evenodd"clip-rule="evenodd"d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"/></svg></button></div><pclassName="text-sm text-slate-700">                Free shipping on all continental US orders.</p></form></div>}
Enter fullscreen modeExit fullscreen mode

This code looks messy and difficult to maintain, and we will look for the atomic components that need to be encapsulated.

Button componenet

Button component is the most common component that we can extract.

So we can do a simple encapsulating.

import{ButtonHTMLAttributes}from"react"typeButtonVariant=|'filled'|'outlined'interfaceButtonPropsextendsButtonHTMLAttributes<HTMLButtonElement>{variant:ButtonVariant;}exportdefaultfunctionButton(props:ButtonProps){const{type,variant,className,children}=props;constvariantClassNames:{[key:string]:string}={filled:'bg-black text-white',outlined:'border border-slate-200 text-slate-900'}return<buttonclassName={`h-10 px-6 font-semibold rounded-md${variantClassNames[variant]}${className}`}type={type}>{children}</button>}
Enter fullscreen modeExit fullscreen mode

then we can use it as.

functionShoppingCard(){return...<divclassName="flex-auto flex space-x-4"><Buttonvariant="filled">Buy now</Button><Buttonvariant="outlined"> Add to bag</Button></div>    ...}
Enter fullscreen modeExit fullscreen mode

Icon component

Alsosvg can been encapsulated as an atomic component.

interfaceIconProps{size?:number}exportdefaultfunctionHeartIcon(props:IconProps){const{size=20}=props;constrate=size/20;return<svgstyle={{transform:`scale(${rate})`}}width='20'height='20'fill="currentColor"aria-hidden="true"><pathfillRule="evenodd"clipRule="evenodd"d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"/></svg>}
Enter fullscreen modeExit fullscreen mode

Radio component

We can find out theRadio component, so we need to encapsulate the<input type="radio" />

import{InputHTMLAttributes}from"react";interfaceRadioPropsextendsInputHTMLAttributes<HTMLInputElement>{label:string;}exportdefaultfunctionRadio(props:RadioProps){const{label,name,value,checked,className,onChange}=props;return<labelclassName="relative cursor-pointer"htmlFor={label}><inputclassName="sr-only peer"type="radio"id={label}value={value}name={name}checked={checked}onChange={onChange}/><divclassName={`min-w-[36px] min-h-[36px] p-2 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white${className}`}>{label}</div></label>}
Enter fullscreen modeExit fullscreen mode

then we can use it like this.

functionShopingCard(){constsizeList=['XS','S','M','L','XL'];constonSizeChange=(event:ChangeEvent<HTMLInputElement>)=>{setCurrentSize(event.target.value);}const[currentSize,setCurrentSize]=useState(sizeList[0])return(...<divclassName="space-x-2 flex text-sm">{sizeList.map(size=><Radiokey={size}name="size"value={size}label={size}checked={currentSize===size}onChange={onSizeChange}/>)}</div>     ...  )}
Enter fullscreen modeExit fullscreen mode

According to the atomic table, we have completed the encapsulation of part of theForm atomic components above. Next, we will identify the types of other atomic components.

Typography component

Document sections

import{PropsWithChildren}from"react";interfaceTypographyPropsextendsPropsWithChildren{className?:string;variant:'h1'|'h2'|'h3'|'h4'|'h5'|'h6'|'lead'|'paragraph'}interfaceTextPropsextendsPropsWithChildren{className?:string;}exportdefaultfunctionTypography(props:TypographyProps){const{variant,children,className}=props;constbaseClassNames='block antialiased tracking-normal font-sans font-semibold';consttypographies={h1:(p:TextProps)=><h1className={`${baseClassNames} text-5xl leading-tight${p.className}`}>{p.children}</h1>,h2:(p:TextProps)=><h2className={`${baseClassNames} text-4xl leading-[1.3]${p.className}`}>{p.children}</h2>,h3:(p:TextProps)=><h3className={`${baseClassNames} text-3xl leading-snug${p.className}`}>{p.children}</h3>,h4:(p:TextProps)=><h4className={`${baseClassNames} text-2xl leading-snug${p.className}`}>{p.children}</h4>,h5:(p:TextProps)=><h5className={`${baseClassNames} text-xl leading-snug${p.className}`}>{p.children}</h5>,h6:(p:TextProps)=><h6className={`${baseClassNames} text-lg leading-relaxed${p.className}`}>{p.children}</h6>,lead:(p:TextProps)=><pclassName={`${baseClassNames} text-base font-normal leading-relaxed${p.className}`}>{p.children}</p>,paragraph:(p:TextProps)=><pclassName={`${baseClassNames} text-sm font-normal leading-relaxed${p.className}`}>{p.children}</p>,}returntypographies[variant]({className,children});}
Enter fullscreen modeExit fullscreen mode

in this component we can see the classname is a little heavy, Tailwind CSS provides@apply decorator, so we can name classname as it's meaning.

.base-font{@applyblockantialiasedtracking-normalfont-sansfont-semibold;}.heading1{@applytext-5xlleading-tight;}.heading2{@applytext-4xlleading-[1.3];}.heading3{@applytext-3xlleading-snug;}.heading4{@applytext-2xlleading-snug;}.heading5{@applytext-xlleading-snug;}.heading6{@applytext-lgleading-relaxed;}.lead{@applytext-basefont-normalleading-relaxed;}.paragraph{@applytext-smfont-normalleading-relaxed;}
Enter fullscreen modeExit fullscreen mode

import{PropsWithChildren,createElement}from"react";import'./style.css';// import styleinterfaceTypographyPropsextendsPropsWithChildren{className?:string;variant:'h1'|'h2'|'h3'|'h4'|'h5'|'h6'|'lead'|'paragraph';}exportdefaultfunctionTypography(props:TypographyProps){const{variant,children,className}=props;constheadingElements=['h1','h2','h3','h4','h5','h6'];consttypographiesClassName={h1:'heading1',h2:'heading2',h3:'heading3',h4:'heading4',h5:'heading5',h6:'heading6',lead:'lead',paragraph:'paragraph'};returncreateElement(headingElements.includes(variant)?variant:'p',{className:`base-font${typographiesClassName[variant]}${className}`},children);}
Enter fullscreen modeExit fullscreen mode

Card

Group content

import{HTMLAttributes}from"react";interfaceCardPropsextendsHTMLAttributes<HTMLDivElement>{}exportdefaultfunctionCard(props:CardProps){const{children,className}=props;return<divclassName={`flex font-sans shadow-md p-2 rounded-xl overflow-hidden${className}`}>{children}</div>}
Enter fullscreen modeExit fullscreen mode

Final ShoppingCard

In the end, our shopping card code became easier to maintain and read than before, and there were actually some small components that could be separated, such as dividers and pictures.

functionShoppingCard(){constsizeList=['XS','S','M','L','XL'];constonSizeChange=(event:ChangeEvent<HTMLInputElement>)=>{setCurrentSize(event.target.value);}const[currentSize,setCurrentSize]=useState(sizeList[0]);return(<divclassName="flex items-center justify-center h-screen"><Card><divclassName="flex-none w-48 relative"><imgsrc="https://www.tailwindcss.cn/_next/static/media/classic-utility-jacket.82031370.jpg"className="w-full h-full object-cover"loading="lazy"/></div><formclassName="flex-auto p-6"><divclassName="flex flex-wrap"><Typographyvariant="h6"className="flex-auto text-slate-900">Utility Jacket</Typography><Typographyvariant="h6"className="text-slate-500">$110.00</Typography><Typographyvariant="lead"className="text-slate-700 mt-2 w-full">In stock</Typography></div><divclassName="flex items-baseline mt-4 mb-6 pb-6 border-b border-slate-200"><divclassName="space-x-2 flex text-sm">{sizeList.map(size=><Radiokey={size}name="size"value={size}label={size}checked={currentSize===size}onChange={onSizeChange}/>)}</div></div><divclassName="flex space-x-4 mb-6 text-sm font-medium"><divclassName="flex-auto flex space-x-4"><Buttonvariant="filled">Buy now</Button><Buttonvariant="outlined"> Add to bag</Button></div><Buttonvariant="outlined"className="px-2.5"><HeartIconsize={24}/></Button></div><Typographyvariant="paragraph"className="text-slate-700">            Free shipping on all continental US orders.</Typography></form></Card></div>)}
Enter fullscreen modeExit fullscreen mode

There are also corresponding instructions in the official website, how to do the splitting of components.

Tailwind official practice

With the separation of Atomic components, the patchwork page will become intuitive and clear, which is the combination of Atomic Component and Atomic CSS, one is the atomic of logic level and the other is the atomic of style level, in this way can truly achieve the Atomic methodology.


Reference

  1. Atomic Design Methodology
  2. material-tailwind-react
  3. Tailwind css
  4. Github of this article

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Frontend developer
  • Location
    ChengDu, SiChuan, China
  • Education
    ChengDu University
  • Work
    Frontend developer in 57blocks.io
  • Joined

More frommarkzzw

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp