/react-native-styl

๐Ÿ’… Micro-library that writes stylesheets with a non-opinionated approach, free of dependencies, and in the easiest way possible.

Primary LanguageTypeScript

styl
npm version dependencies bundlephobia

react-native-styl is a micro-library for React Native developers whose goal is to write stylesheets with a non-opinionated library, free of dependencies, and in the easiest way possible.

import styl from 'react-native-styl'
import { Text } from 'react-native'

const Title = styl(Text)({ color: 'blue' })

const App = () => <Title>Styl</Title>

Motivation

  • Keep the stylesheet simple: the recommended approach to writing stylesheets in React Native still needs too much boilerplate and it's a pain to maintain; styl provides a simple API where you'll be able to write the same stylesheets you are used to โ€“ with fewer lines of code;

  • Performance: no magic or tricks here, styl just maps the stylesheet (which can come from inline-style, the function argument or even props) to the style prop in the component: one of the most performative ways to write styles in React Native;

  • Versatility: styl uses the context API to bring full theme support, which can be used throughout the application; components can also be easily extended and styled overrided when needed;

  • Ultralightweight: about 1kb.

Usage

To get started using react-native-styl, first install the package:

yarn add react-native-styl or npm i react-native-styl

Styling native elements:

Styl is a high-order function that receives any component that supports the style prop, and returns a function that expects a plain object stylesheet. It will return a styled React component with the same props of the original component:

import styl from "react-native-styl"
import { ScrollView } from "react-native"

const Wrapper = styl(ScrollView)({
  padding: 16
})

<Wrapper indicatorStyle="black">
  <View />
</Wrapper>
Dynamic styles:

Easily create dynamic stylesheets. Use a callback function to access the component props when creating the styles:

import styl from "react-native-styl"
import { Text } from "react-native"

const ColoredText = styl(Text)(({ props }) => ({
  color: props.color,
}))

<ColoredText color="red">Lorem ipsum</ColoredText>
Theming:

Wrap your application with the Provider and every component will also have access to the theme in the callback function:

import { styl, Provider as StyleProvider } from "react-native-styl"
import { Text } from "react-native"

const Theme = ({ children }) => (
  <StyleProvider theme={{ primary: 'blue' }}>
    {children}
  </StyleProvider>
)

const ThemeColorText = styl(Text)(({ theme }) => ({
  color: theme.primary
}))

<ThemeColorText>Lorem ipsum</ThemeColorText>
useTheme:

The useTheme hook let you access the currently active theme.

import { useTheme, Provider as StyleProvider } from 'react-native-styl'

const Main = ({ children }) => {
  const theme = useTheme()

  return <Text style={{ color: theme.brand }}>Foo</Text>
}

const App = () => {
  return (
    <StyleProvider theme={{ color: { brand: 'blue' } }}>
      <Main />
    </StyleProvider>
  )
}
Extends:

Given that styl accepts any component that supports the style prop, every component created by the library can be styled again. It will inherit the original component style that can be extended:

import styl from "react-native-styl"
import { Text } from "react-native"

const BaseText = styl(Text)({
  color: 'red',
  padding: 16,
})

const ExtendedText = styl(BaseText)({
  color: 'green',
})

<ExtendedText>Lorem ipsum</ExtendedText>
Polymorphic elements: `as` prop

Render a new styled component passing a valid React component to as prop:

import styl from "react-native-styl"
import { Text, TouchableOpacity } from "react-native"

const Base = styl(Text)({
  padding: 16
})

<Base as={TouchableOpacity} onPress={() => null}>
  <Text>TouchableOpacity</Text>
</Base>
Presets components:

The first argument of react-native-styl accepts any valid React component. This means it's possible to pass a custom function component:

import styl from "react-native-styl"
import { Text } from "react-native"

const PresetComp = styl((props) => (
  <Text ellipsizeMode="tail" numberOfLines={1} {...props} />
))({ padding: 16 })

<PresetComp>Lorem ipsum</PresetComp>
TypeScript:

react-native-styl fully supports TypeScript for both theme definitions and custom props.

Theme definition: The first step is to create a declarations file (e.g.: theme.d.ts), with the following content:

// import original module declarations
import 'react-native-styl'

// and extend it
declare module 'react-native-styl' {
  export interface DefaultTheme {
    colors: {
      main: string
      secondary: string
    }
  }
}

Custom props:

Define the component props and pass it to the main function:

import styl from "react-native-styl"
import { Text } from "react-native"

interface TitleProps {
   color: string
}

const Title = styl(Text)<TitleProps>(({ props }) => ({
  color: props.color,
}))

<Title color="blue">Lorem ipsum</Title>

as prop

Typescript is not yet supported Help is needed to implement it.

Styled-API-like:

Create a custom library to suit your own goals:

import styl from 'react-native-styl'
import * as RN from 'react-native'

const UI = {
  View: styl(RN.View),
  Text: styl(RN.Text),
}

const Title = UI.Text({ color: 'red' })

More examples in examples/src.


Benchmark

Internal tests rendering 5k views and 10k views into a Scrollview, styl shows to be one of the most performative ways to write stylesheets in React Native, losing only to the native approaches. The results below are the average of 5 complete renders measured in milliseconds:

Library Rendering 5k Views Rendering 10k Views
StyleSheet 2068ms 4095ms
Inline-style 2317ms 4507ms
react-native-styl 2754ms 5432ms
Styled-components 3102ms 6460ms

See the tests in examples/src

Others benchmarks that are worth mentioning:

Inspiration:

This package was inspired by people's work on the following projects:

Special thanks to:

License:

MIT License ยฉ Danilo Woznica