Theme Configuration
Augmenting your theme to suit your needs
Overview
Theming is hardly a one-size-fits-all topic, with as many different ways to use themes as
there are people using them. It's for this reason that Jynx
remains relatively agnostic
when it comes to how you want to define your theme
.
There are minimal requirements when specifying your scale
s and
key
s, but the rest of the organizational structure is left totally down to you.
Whether your storing a few color values or building out an entire design system, Jynx
is
flexible enough to allow your theme
to morph and scale as your requirements change.
However, there are a few 'best practices' you'll want to be aware of in order to get the
most out of your theme
, which are detailed below.
Scales
Theme values are defined using scale
s which can be either an array
or an object
and
allow you to specify a series of associated values that can then be accessed from certain
props.
When it comes to then using these values in your components:
- single-level array-based scale values can be accessed using numbers
- single-level object-based scale values can be accessed using string-keys
export const theme = {
colors: {
red: '#F2335D',
orange: '#FE8400',
yellow: '#FFCC00',
green: '#7CD420',
blue: '#12A5EC',
purple: '#7753F8'
},
space: [0, 2, 4, 8, 16, 24, 32, 48, 64, 128]
}
/* theme.colors.orange */
<Component bgColor='orange' />
/* theme.space[4] (16) */
<Component m={4} />
Defining values
The way you define the values within your scales is completely up to you, providing you're
using valid CSS values (usually string | number
).
However, depending on the corresponding props accessing a scale, there are a a few different ways that its values can be interpreted.
Scales with numeric values
The following scales usually specify numeric (often length-based) values:
space
fontSizes
fontWeights
lineHeights
letterSpacings
borderWidths
radii
zIndices
You can define your values for these scales as string
s, number
s, with units, without
units or a mixture of the preceding, and they will be parsed accordingly:
number
s and numericstring
s (i.e.16
|'16'
) are converted topx
where appropriatestring
s with units honour the declared unitstring
s without units resolve to a raw CSS value- you can even use a function, as long it returns
string | number
export const theme = {
/* scales can be defined as either an object or an array */
fontWeights: {
light: 300,
regular: 400,
medium: 500,
bold: 700
},
space: [0, 2, 4, 8, 16, 24, 32, 48, 64, 128],
/* numbers and numeric strings are converted to `px`
where appropriate */
borderWidths: [0, 1, 1.5, 2,], // will be converted
radii: ['0', '2', '4', '8'], // will be converted
lineHeights: [300, 400, 500, 700] // will `not` be converted
/* strings with units honour the defined unit */
fontSizes: [
'0.75rem',
'1rem',
'1.5rem',
'2rem',
'3rem',
'4rem',
'5rem'
],
/* strings without units return the raw CSS value*/
fontWeights: [
'light',
'regular',
'medium',
'bold',
],
/* you can even use a function (providing the return type
is {string | number}) */
letterSpacings: [
pxToRem(0), // 0rem
pxToRem(2), // 0.125rem
pxToRem(4), // 0.25rem
pxToRem(8) // 0.5rem
]
}
Scales with string values
The following scales usually specify string values:
colors
fonts
borders
borderStyles
shadows
transitions
You should ideally define your values for these scales as strings:
export const theme = {
/* scales can be defined as either an array or an object */
borders: {
primary: '1px solid hsla(266, 100%, 65%, 1)',
active: '1px solid hsla(266, 100%, 65%, 0.5)'
disabled: '1px solid #eee'
},
borderStyles: [ 'solid', 'dashed'],
/* Any valid string value can be used, meaning you can define
colors any way you normally would */
colors: {
red: 'red', // color keywords
orange: '#FF8400', // hex values
yellow: 'rgb(255, 204, 0)', // rgb values
green: 'hsl(89, 74%, 48%)', // hsl values
blue: 'rgba(18, 164, 237, 1)', // rgba values
purple: 'hsla(253, 92%, 65%, 1)' // hsla value
}
}
Nesting
In addition to defining scale
s as objects/arrays of string
s/number
s you also have
the option to nest objects and arrays to create a more complex design system.
This can be useful in situations where you have a larger asset library or just want more
granular control over the organization of your theme
.
export const theme = {
colors: {
neutrals: [
'#F9FAFB',
'#F3F4F6',
'#E5E7EB',
'#D1D5DB',
'#9CA3AF',
'#6B7280',
'#4B5563',
'#374151',
'#1F2937',
'#111827'
],
accent: {
primary: 'hsla(126deg, 45%, 44%, 1)',
secondary: 'hsla(146deg, 50%, 70%, 0.625)'
},
brand: {
purples: ['#622a87', '#7c2eb0', '#9c30e3'],
pinks: ['#8f1378', '#c204bb', '#e330dd'],
blues: ['#13828f', '#25abba', '#2dd8eb']
}
}
}
/* Access the values through bracket notation */
/* theme.colors.brand.pinks[1] */
<Component color='brand.pinks[1]' />
/* Or through dot notation */
/* theme.colors.neutrals[5] */
<Component bgColor='neutrals.5' />
Cross-referencing
When constructing your theme
, you may run into instances where you want to reference one
theme value from within another.
An example of this would be wanting to reference the colors
scale to specify a
border-color
in your borders
scale.
export const theme = {
colors: {
red: '#F2335D',
orange: '#FE8400',
yellow: '#FFCC00',
green: '#7CD420',
blue: '#12A5EC',
purple: '#7753F8'
},
borders: {
primary: `1px solid ${this.colors.green}` // this won't work...
}
}
So how can we do this?
The recommended solution here is to abstract your scale
s into individual variables and
then aggregate these into a single exported theme
object.
/* define an individual `colors` scale */
const colors = {
red: '#F2335D',
orange: '#FE8400',
yellow: '#FFCC00',
green: '#7CD420',
blue: '#12A5EC',
purple: '#7753F8'
}
/* define an individual `borders` scale, referencing the `colors` object */
const borders = {
primary: `1px solid ${colors.green}` // this will work!
}
/* export a global theme object of the combined scales */
export const theme = {
colors,
borders
}
This can also be helpful if you want to map existing values to alternate names whilst maintaining a particular theme structure.
/* define an individual `colors` scale */
const scale = {
red: '#F2335D',
orange: '#FE8400',
yellow: '#FFCC00',
green: '#7CD420',
blue: '#12A5EC',
purple: '#7753F8'
}
/* define an individual `elements` scale mapping values to from
the `scale` object to html elements */
const elements = {
headings: scale.purple,
paragraph: scale.red,
blockquote: scale.orange
}
/* export a global theme object with the two nested scales */
export const theme = {
colors: {
scale,
elements
}
}
/* and access the value from your component */
/* theme.colors.elements.heading */
<Heading color='elements.heading' />
/* or combine the two scales using ES9 spread syntax and export a
global theme object with a single colors scale */
export const theme = {
colors: {
...scale,
...elements
}
}
/* and access the value from your component */
/* theme.colors.blockquote */
<Blockquote bgColor="blockquote" />
Breakpoints
The breakpoints scale is the most important scale within the theme
object and is the
only scale to have default values.
/* Default breakpoints */
export const theme = {
breakpoints: {
sm: 640,
md: 960,
lg: 1280,
xl: 1440,
xxl: 1600
}
}
These values are integral to making responsive styles work (hence why they're predefined) but can easily be customized to work with your own design system.
Defining custom breakpoints
Like any other scale, breakpoints
can be defined as an object or an array and can
contain string values with units (e.g. '40em'
) or plain numbers which will be converted
to px
.
How you chose to define your breakpoints is completely up to you. There's no restrictions on the denomination used or the number of values specified, however, one requirement is that the scale must be only one level deep.
Jynx
does not currently have support for nested breakpoint scales.
// numeric, array-based scale
export const theme = {
breakpoints: [540, 720, 1080, 1440]
}
// numeric, object-based scale
export const theme = {
breakpoints: {
mobile: 540,
tablet: 720,
laptop: 1080,
desktop: 1440
}
}
// string, array-based scale
export const theme = {
breakpoints: ['40em', '60em', '80em']
}
// string, object-based scale
export const theme = {
breakpoints: {
mobile: '40em',
tablet: '60em',
laptop: '80em',
desktop: '100em'
}
}
Read more about how
Jynx
uses thebreakpoints
scale to create mobile-first, responsive styles by visiting the responsive styles page.
Keys
Theme scales are accessed by the key
they're assigned too within the theme
object,
with many style function props having a specific key
they use to access their
corresponding theme scale.
In most cases, this correlates with the CSS properties it's used for (border-width
uses
borderWidths
, etc), however, certain key
s are used with multiple CSS properties when
they share they same type of value (margin
and padding
both use space
).
Reference Table
key | properties |
---|---|
breakpoints | |
space | gap , column-gap , row-gap , width , height , min-width , min-height , max-width , max-height top , right , left , bottom , margin , margin-top , margin-right , margin-bottom , margin-left , margin-block , margin-block-start , margin-block-end , margin-inline , margin-inline-start , margin-inline-end , padding , padding-top , padding-right , padding-bottom , padding-left , padding-block , padding-block-start , padding-block-end , padding-inline , padding-inline-start , padding-inline-end |
fontSizes | font-size |
colors | border-color , border-top-color , border-right-color , border-bottom-color , border-left-color , color , background-color |
fonts | font-family |
fontWeights | font-weight |
lineHeights | line-height |
letterSpacings | letter-spacing |
borders | border , border-top , border-right , border-bottom , border-left |
borderStyles | border-style , border-top-style , border-right-style , border-bottom-style , border-left-style |
borderWidths | border-width , border-top-width , border-right-width , border-bottom-width , border-left-width |
radii | border-radius , border-top-left-radius , border-top-right-radius , border-bottom-left-radius , border-bottom-right-radius |
shadows | box-shadow , text-shadow |
transitions | transition |
zIndices | z-index |
Exclusions
There are some CSS properties, such as display
or align-items
, that only accept a
small number of predetermined strings as valid values. Thanks to the type-safe nature of
Jynx
, your IDE should be aware of these values and provide them to you as suggestions
when using the correlating props.
Therefore they should not be included in your theme.
Other props that come under this rule include: overflow
, position
, justify-content
,
flex-direction
, vertical-align
and text-align
.
Types
A full rundown of the types associated with the theme
can be found on the
types page or use the links below to jump to a specific type: