Jynx logoJynx

Theme Setup

How to implement a global theme

Overview

In order to create consistent and coherent styles throughout a project, it can often be beneficial to use a theme object to store and access common style values and scales.

Jynx allows you to define a theme object that can then be distributed to all of your styled components with the added benefit of providing type assertions and input suggestions to props that access defined theme scales.

As a basic example:

/* theme.ts */
export const theme = {
  colors: {
    primary: '#e32020',
    secondary: '#1b92c4'
  }
}


/* Layout.tsx */
export const Container = styled.div<ColorProps>`
  ${color}
`

export const Layout: React.FC = ({ children }) => {
  return (
    // The values 'primary' and 'secondary' will be suggested here
    //                  ⌄⌄
    <Container bgColor=' '>
     {children}
    </Container>
  )
}

Process

The process for setting up your theme requires 2-3 steps:

  1. define your theme
  2. wrap your app in a ThemeProvider and pass your theme to it
  3. (optionally) declare your theme's types

1. Define your theme

You can define your theme however you like, the only requirement is that it's an object. However, to make your values accessible to certain functions, you do need to define them under specific keys (check the API reference to see which props correspond to which keys).

The simplest way to define your theme is to create a theme.ts/.js file and export your it from there:

/* theme.ts */
export const theme = {
  breakpoints: {
    sm: '640px',
    md: '960px',
    lg: '1280px'
  }
}

2. Add a ThemeProvider

The next step is to wrap your entire app in a ThemeProvider and pass it the exported theme - thereby making it accessible across your entire app.

Most CSS-in-JS libraries provide you with a ThemeProvider component to use in this situation. The example below is written using 'styled-components'.

/* App.ts */
import { ThemeProvider } from 'styled-components'
import { theme } from '../theme.ts'

const App: React.FC = props => (
    <ThemeProvider theme={theme}>
      {/* application content */}
    </ThemeProvider>
  )

export default App

If you're not using Typescript then that's it, you're all set!

However, if you are using Typescript, you'll most likely want to make your theme type-safe, which means an additional step...

3. Declaring your types

As of v4.1.4, Typescript has allowed type definitions to be extended through declaration merging. We can use this to provide Jynx with type information about our theme which will then permeate across the rest of our app.

Accessing your theme type

To begin with, you need to get the type definition of your theme. Whilst you can define this manually, the recommended way is to export a type from your theme.ts/.js file that is the typeof your theme object:

/* theme.ts */
export const theme = {
  breakpoints: {
    sm: '640px',
    md: '960px',
    lg: '1280px'
  }
}

export type Theme = typeof theme

This way, as you expand, update and make changes your theme, your type declarations will reactively update too.

Creating a declarations file

Once you have your theme type, you'll then need to create a declarations file. Name it 'jynx.d.ts' (or another name of your choice).

/* import the existing declarations */
import 'jynx'

/* and your custom `Theme` type */
import type { Theme } from '@/themes'


/* Then declare the `jynx` module */
declare module 'jynx' {
/* and extend the `CustomTheme` interface with your own `Theme` type */
  export interface CustomTheme extends Theme {}
}

The CustomTheme type being extended is just an empty interface that's used as part of the library's DefaultTheme type which conditionally resolves to the correct theme depending on whether a custom theme is defined.

And there you have it! Your themes types have now been declared and any style functions you use will have access to them.

If you're using a library like styled-components or emotion then it's more than likely you'll be familiar with this process and will be doing it for that library too.

Make sure you complete this process as this declaration file only adds types to the jynx functions and not to the components they're used in.