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 scales and
keys, 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 scales 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:
spacefontSizesfontWeightslineHeightsletterSpacingsborderWidthsradiizIndices
You can define your values for these scales as strings, numbers, with units, without
units or a mixture of the preceding, and they will be parsed accordingly:
numbers and numericstrings (i.e.16|'16') are converted topxwhere appropriatestrings with units honour the declared unitstrings 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:
colorsfontsbordersborderStylesshadowstransitions
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 scales as objects/arrays of strings/numbers 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 scales 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
Jynxuses thebreakpointsscale 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 keys 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: