Retour d'XP sur Chakra UI

Une lib de composants modulaire, accessible et typée

Godefroy de Compreignac, co-fondateur @ Lonestone

Meetup React Nantes - 31 mars 2022

Vous connaissez peut-être

 

Material UI

Ant Design

Semantic UI

Reakit

Element UI

Grommet

...

 

Ces libs sont très pratiques,

mais elles m'ont parfois
donné du fil à retordre...

Manque de modularité


-> Styling différent pour les composants custom

Manque de composants (Reakit)


-> Apport de composants avec un style différent ou une mauvaise accessibilité

Styling difficile à maintenir

avec CSS modules, CSS-in-JS  (Material)
ou styled components

Personnalisation difficile des balises contenues dans certains composants (Ant Design)


-> Hacks bizarres pour personnaliser comme on veut

J'aime bien l'approche de Tailwind
qui aide à aller vite, mais :

  • Pas de logique intégrée (@headlessui/react nécessaire)
  • Pas d'autocomplétion sans extension d'éditeur

Et puis j'ai découvert Chakra UI

Un petit nouveau qui cartonne !

J'ai choisi Chakra pour développer
mon dernier SaaS :

Rolebase.io
(pas encore annoncé et pas de page
de présentation pour le moment)

 

 

Développement commencé de plusieurs webapps avec Chakra chez Lonestone

Installation

npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
import { ChakraProvider } from '@chakra-ui/react'

ReactDOM.render(
  <ChakraProvider>
    <App />
  </ChakraProvider>,
  document.getElementById('root'),
)

Chakra a besoin de emotion (styled) et de framer-motion,


mais on a rarement besoin de les utiliser explicitement.

FORMS

Button

Checkbox

Editable

Form Control

Icon Button

Input

Number Input

Pin Input

Radio

Range Slider

Select

Slider

Switch

Textarea

Composants principaux

LAYOUT

Aspect Ratio

Box

Center

Container

Flex

Grid

SimpleGrid

Stack

Wrap

DATA DISPLAY

Badge

Code

Divider

Kbd

List

Stat

Table

Tag

FEEDBACK

Alert

Circular Progress

Progress

Skeleton

Spinner

Toast

TYPOGRAPHY

Text

Heading

OVERLAY

Alert Dialog

Drawer

Menu

Modal

Popover

Tooltip

DISCLOSURE

Accordion

Tabs

Visually Hidden

NAVIGATION

Breadcrumb

Link

LinkOverlay

MEDIA AND ICONS

Avatar

Icon

Image

OTHER

Close Button

Portal

Show / Hide

Transitions

La brique de base, c'est <Box>.

 

Le style se fait par les props :

<Box padding="10px" background="#eee">
  Lorem ipsum
</Box>

Mais rien à voir avec style={{ ... }}

 

Des classes CSS sont automatiquement

gérées sous le capot par emotion.

On peut utiliser des raccourcis à la Tailwind :

<Box p="10px" bg="#eee">
  Lorem ipsum
</Box>

On trouve en général les raccourcis intuitivement :

 

  • m = margin
  • mt = margin-top
  • mr = margin-right
  • mb = margin-bottom
  • ml = margin-left
  • p = padding
  • pt = t'as deviné...
  • bg = background
  • w = width
  • h = height

Le typing est 👌👌👌

Les valeurs en dur, on va éviter !

 

On utilise autant que possible des valeurs du thème :

<Box p={3} bg="gray.200">
  Lorem ipsum
</Box>

-> Marges, couleurs, polices, radius, tout est configurable dans un thème centralisé et typé.

Il y aussi tout un tas de props pour styliser en fonction de pseudo-sélecteurs ou de l'état des composants :

_hover, _checked, _dark, _light...

<Box
  p={3}
  bg="gray.200"
  _hover={{
    bg: 'gray.300',
  }}
>
  Lorem ipsum
</Box>

Comment intégrer ça ?

import * as React from 'react'
import { Box, Center, Image, Flex, Badge, Text } from '@chakra-ui/react'
import { MdStar } from 'react-icons/md'

export default function Card() {
  return (
    <Center h="100vh">
      <Box p="5" maxW="320px" borderWidth="1px">
        <Image borderRadius="md" src="photo.jpg" />
        <Flex align="baseline" mt={2}>
          <Badge colorScheme="pink">Plus</Badge>
          <Text
            ml={2}
            textTransform="uppercase"
            fontSize="sm"
            fontWeight="bold"
            color="pink.800"
          >
            Verified &bull; Cape Town
          </Text>
        </Flex>
        <Text mt={2} fontSize="xl" fontWeight="semibold" lineHeight="short">
          Modern, Chic Penthouse with Mountain, City & Sea Views
        </Text>
        <Text mt={2}>$119/night</Text>
        <Flex mt={2} align="center">
          <Box as={MdStar} color="orange.400" />
          <Text ml={1} fontSize="sm">
            <b>4.84</b> (190)
          </Text>
        </Flex>
      </Box>
    </Center>
  )
}

Pour étendre le thème :

import { extendTheme } from '@chakra-ui/react'

const theme = extendTheme({
  config: {
    initialColorMode: 'light',
    useSystemColorMode: false,
  },
  colors: {
    black: '#37352f',
  },
  shadows: {
    outline: '0 0 3px 0px #000',
  },
  components: {
    Link: {
      baseStyle: {
        textDecoration: 'underline',
      },
    },
  },
})

export default theme
<ChakraProvider theme={theme}>

Et on le fournit au provider :

Le "color mode" pour faire un thème dark/light est facile à utiliser.

import { MenuItem, useColorMode } from '@chakra-ui/react'
import React from 'react'
import { FiMoon, FiSun } from 'react-icons/fi'

export default function ThemeToggle() {
  const { colorMode, toggleColorMode } = useColorMode()

  return (
    <MenuItem
      icon={colorMode === 'light' ? <FiSun /> : <FiMoon />}
      onClick={toggleColorMode}
    >
      Thème clair/sombre
    </MenuItem>
  )
}
<Box
  p={3}
  bg="gray.200"
  _dark={{
    bg: 'gray.600',
  }}
>
  Lorem ipsum
</Box>

Exemple de composant custom avec dark theme :

Des features bien pensées
et extensibles.

 

Par exemple pour les boutons :

<Stack direction='row' spacing={4}>
  <Button colorScheme='green' variant='solid'>
    Button
  </Button>
  <Button colorScheme='blue' variant='outline'>
    Button
  </Button>
  <Button colorScheme='red' variant='ghost'>
    Button
  </Button>
  <Button colorScheme='teal' leftIcon={<ArrowForwardIcon />}>
    Button
  </Button>
</Stack>

Comment étendre un composant ?

 

Une manière que j'aime bien :

import { Button, ButtonProps } from '@chakra-ui/react'
import { CircleWithRoleEntry } from '@shared/circle'
import React from 'react'
import CircleMemberLink from './CircleMemberLink'

interface Props extends ButtonProps {
  circle: CircleWithRoleEntry
}

export default function CircleButton({ circle, ...buttonProps }: Props) {
  return (
    <CircleMemberLink circleId={circle.id} tabIndex={-1}>
      <Button size="sm" borderRadius="full" {...buttonProps}>
        {circle.role.name}
      </Button>
    </CircleMemberLink>
  )
}

Quelques hooks inclus bien utiles

 

En particulier :

  • useDisclosure pour les modales
     
  • useDimensions pour observer les dimensions d'un élément
     
  • useBreakpointValue pour faire des variants en fonction de breakpoints
     
  • useMediaQuery pour détecter des tailles et types d'écran
     
  • useOutsideClick pour détecter un click en dehors d'un élément

J'ai beaucoup aimé utiliser Chakra,

je trouve que j'obtiens du code :

  • Concis
  • Modulaire
  • Bien typé
  • Avec peu de redondance

 

et une UI :

  • Cohérente
  • Accessible

Il y a un kit Figma pour nos amis designers :

https://www.figma.com/community/file/971408767069651759

Merci !

Vous avez des questions ?

Je suis Godefroy de Compreignac, co-fondateur de Lonestone.
Si ça vous a plu, suivez-moi sur Twitter @Godefroy
et Linkedin
,
mettez un pouce bleu, postulez chez Lonestone

Retour d'XP sur Chakra UI

By lonestone

Retour d'XP sur Chakra UI

  • 332