@styled-kit/mods
v1.1.0
Published
Allows you to write modifiers for Styled Components and Linaria with autocomplete. As well as automatically generate for them types.
Downloads
5,145
Maintainers
Readme
Modifiers with autocomplete for Styled Components and Linaria
This library allows you to write modifiers for Styled Components and Linaria via Dot Notation and with autocomplete. As well as automatically generate for them types. And that's not all :sunglasses:.
Features
- Quickly writing styles in relation to modifiers
- Using modifiers via Dot Notation
- Writing modifiers with autocomplete
- Uniform modifiers and their values
- Automatic type generation for modifiers
- Possibility to use custom modifiers
- Applying styles relative to multiple modifiers or multiple values
- Ultra-small size (0.4 KB gzip)
A Quick Look
Demo
Usage
Apply styles for any size
property value or any color
value:
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<Mods<'size' | 'color'>>`
// Call as literals
${mods.size`
padding: 20px;
margin: 32px;
`};
// Call as function
${mods.color(
(value) => css`
color: ${value};
border: 1px solid;
`
)};
`;
<StyledComponent color="blue" size="small" />
Apply styles for size='small'
or disabled={true}
:
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<
Mods<'size', 'small' | 'medium'> & Mods<'disabled'>
>`
${mods.size.small`
font-size: 14px;
`};
${mods.size.medium`
font-size: 16px;
`};
${mods.disabled.true`
color: gray;
`};
${mods.disabled.false`
color: black;
`};
`;
<StyledComponent size="small" disabled />
Apply styles if size
is undefined
or color
is not blue
:
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<Mods<'size' | 'color'>>`
${mods.not.size`
font-size: 14px;
`};
${mods.not.color.blue`
background: transparent;
`};
`;
<StyledComponent color="green" />
Apply styles for any value of the customProp
property:
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<{ customProp: string }>`
${mods('customProp')`
background: black;
`};
`;
<StyledComponent customProp="something" />
Apply styles for customProp='customValue'
:
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<{ customProp: string }>`
${mods('customProp', 'customValue')`
background: black;
`};
`;
<StyledComponent customProp="customValue" />
:point_up: These are not all possible uses of modifiers. View more options
Setup
src/shared/styled/config.ts
// Configure modifier names and their values
const config = {
color: ['red', 'green', 'blue'],
size: ['small', 'medium', 'large'],
spacing: [8, 12],
disabled: [true, false],
} as const;
src/shared/styled/types.ts
import { ModifiersConfig, Modifiers } from '@styled-kit/mods';
// Creating types for modifiers
type ModsConfig = ModifiersConfig<typeof config>;
export type Mods<
Names extends keyof ModsConfig = keyof ModsConfig,
Value extends ModsConfig[Name] = undefined
> = Modifiers<ModsConfig, Name, Value>;
src/shared/styled/index.ts
import { initMods } from '@styled-kit/mods';
import { config } from './config';
// Initializing modifiers by config
export const mods = initMods(config);
export type { Mods } from './types';
Documentation
Installation
You can install the library using the npm
or Yarn
package manager.
Installation example using npm
:
npm install @styled-kit/mods
An example installation using Yarn
:
yarn add @styled-kit/mods
Setup
To be able to use modifiers via Dot Notation, you must define in advance what they can be and what their values are.
Creating a modifiers configuration
To configure modifiers, create a config
configuration object.
You can create this object in any file in your project, but as an option, you can make such a file system:
src/shared/styled/config.ts
const config = {
color: ['red', 'green', 'blue'],
size: ['small', 'medium', 'large'],
spacing: [8, 12],
disabled: [true, false],
} as const;
Describe in config
what modifiers with what values you can have.
Describe those modifiers that you are going to reuse in different components.
Over time, you can add to this object as new modifiers are needed.
Note: In TypeScript you must specify the as const
type for the config
object,
to fix its values and ensure that typing works correctly.
Creating a types
To use autocomplete and types for modifiers, you must configure the appropriate TypeScript types.
You can make type settings in any file of your project, but as an option, you can make such a file system:
src/shared/styled/types.ts
import { ModifiersConfig, Modifiers } from '@styled-kit/mods';
type ModsConfig = ModifiersConfig<typeof config>;
export type Mods<
Names extends keyof ModsConfig = keyof ModsConfig,
Value extends ModsConfig[Name] = undefined
> = Modifiers<ModsConfig, Name, Value>;
export type RMods<
Names extends keyof ModsConfig = keyof ModsConfig,
Value extends ModsConfig[Name] = undefined
> = Required<Mods<Name, Value>>;
ModsConfig
is a type representing the configuration structure of modifiers.
It is only needed to create a Mods
type.
Mods
is a type representing modifiers, where N
is the name of the modifier,
and V
is the value of the modifier (optional). All modifiers can be undefined
.
RMods
This is a copy of Mods
, but all modifiers Required
and cannot be undefined
.
Initializing the modifiers
You can initialize the modifiers in any file of your project, but
it is important that the initialization is done only once at application startup.
The mods
object can then be reused in components of your application.
src/shared/styled/index.ts
import { initMods } from '@styled-kit/mods';
import { config } from './config';
export const mods = initMods(config);
export type { Mods, RMods } from './types';
Initializing options
When initializing modifiers, you can set some options.
export const mods = initMods(config, {
onlyFalseValues: true,
});
onlyFalseValues
(default: false
)
If true
, then modifiers with value false
will not work when undefined
is set.
onlyFalseValues: true
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<Mods<'disabled'>>`
${mods.disabled.false`
color: blue;
`};
`;
// Styles will not be applied because disabled = undefined
<StyledComponent />
onlyFalseValues: false
import { mods, Mods } from '../shared/styled';
export const StyledComponent = styled.div<Mods<'disabled'>>`
${mods.disabled.false`
color: blue;
`};
`;
// Styles will be applied
<StyledComponent />
Usage types
Type Mods
This type allows you to define which properties a particular Styled Component can take.
Mods<'size'>
- returns the type of object with the size
modifier, with all its values from config
:
type ComponentProps = Mods<'size'>;
// ComponentProps = {
// size?: 'small' | 'medium' | 'large';
// }
Mods<'size' | 'disabled'>
- returns object type with size
and disabled
modifiers, with all their values
from config
:
type ComponentProps = Mods<'size' | 'disabled'>;
// ComponentProps = {
// size?: 'small' | 'medium' | 'large';
// disabled?: boolean;
// }
Mods<'size', 'small' | 'large'>
– Returns the object type with the size
modifier, with small
and large
values:
type ComponentProps = Mods<'size', 'small' | 'large'>;
// ComponentProps = {
// size?: 'small' | 'large';
// }
Mods<'size', 'small'> & Mods<'disabled', true> & Mods<'spacing', 12>
– returns the object type with size
, disabled
and spacing
modifiers, with the selected values:
type ComponentProps = Mods<'size', 'small'> &
Mods<'disabled', true> &
Mods<'spacing', 12>;
// ComponentProps = {
// size?: 'small';
// disabled?: true;
// spacing?: 12;
// }
Type RMods
As stated earlier, this is a copy of the Mods
type, but wrapped in Required
. This removes the possibility of passing
a undefined
value to the modifier.
You may need RMods
if you want to make the modifier required:
interface ComponentProps extends RMods<'size'> {}
// interface ComponentProps {
// size: 'small' | 'medium' | 'large';
// }
Type StyledMods
Since version 16 of
React all specified attributes remain on DOM elements
and are not removed even if React does not recognize them. That said, if these attributes are not known to React,
you will see a Warning
in the developer console in the browser.
To avoid these warnings, Styled Components recommends use
prefix $
in front of properties that should not be included in the DOM element.
The StyledMods
type will allow you to write Styled Component property types without the $
prefix,
but still have valid typing. Internally, it prefixes all types passed to it with $
to all the types passed to it.
Without the StyledMods
type:
export const StyledComponent = styled.div<Mods<'size'> & { padding: string; }>`
${mods.size.small`
font-size: 14px;
`};
padding: ${({ padding }) => padding};
`;
<StyledComponent size="small" padding="12px" />
With the StyledMods
type:
import { StyledMods } from '@styled-kit/mods';
export const StyledComponent = styled.div<
StyledMods<Mods<'size'> & { padding: string }>
>`
${mods.size.small`
font-size: 14px;
`};
padding: ${({ $padding }) => $padding};
`;
<StyledComponent $size="small" $padding="12px" />
:point_up: You do not need to add the $
prefix to the mods
modifiers. Modifiers are automatically searched with and without the prefix.
Usage modifiers
The library assumes a large number of options for using modifiers. Each of them can be called as a literal, as a function, with negation, without negation, in object mode or in function mode.
Let's take a closer look at how modifiers can be used:
Using in Object mode
The Object mode
allows you to use Dot Notation to use modifiers that you enter in config
beforehand.
This mode is best suited for applying styles relative to common modifiers that will be reused in other components.
The features of Object mode
modifiers:
- Writing modifiers with Dot Notation
- When writing modifiers, you will have autocomplete
- Types will be automatically generated based on your
config
, which you can use with theMods
type that you create when you initialize the library - You will get modifiers that are reused throughout the project in a single format
Styles will be applied if:
color
is not undefined
export const ModsColor = styled.div<Mods<'color'>>`
${mods.color`
color: blue;
`};
`;
<ModsColor color="blue" />
color
is undefined
export const ModsNotColor = styled.div<Mods<'color'>>`
${mods.not.color`
color: blue;
`};
`;
<ModsNotColor />
color
is blue
and is not undefined
export const ModsColorBlue = styled.div<Mods<'color'>>`
${mods.color.blue`
color: blue;
`};
`;
<ModsColorBlue color="blue" />
color
is not blue
and is not undefined
export const ModsNotColorBlue = styled.div<Mods<'color'>>`
${mods.not.color.blue`
color: white;
`};
`;
<ModsNotColorBlue color="white" />
Using in Function mode
The Function mode
allows you to apply styles using modifiers that are not in your config
.
This mode is best suited for applying styles relative to private modifiers which will not be reused in other components.
The features of Function mode
modifiers:
- Using custom modifiers that are not in
config
- Ability to specify styles relative to multiple modifiers
- Ability to specify styles relative to multiple modifier values
- Types for them are written manually
- No autocomplete when writing
Styles will be applied if:
color
is not undefined
export const FnModsColor = styled.div<{ color?: string }>`
${mods('color')`
color: blue;
`};
`;
<FnModsColor color="blue" />
color
is undefined
export const FnModsNotColor = styled.div<{ color?: string }>`
${mods.not('color')`
color: blue;
`};
`;
<FnModsNotColor />
color
is blue
and is not undefined
export const FnModsColorBlue = styled.div<{ color?: string }>`
${mods('color', 'blue')`
color: blue;
`};
`;
<FnModsColorBlue color="blue" />
color
is not blue
and is not undefined
export const FnModsNotColorBlue = styled.div<{ color?: string }>`
${mods.not('color', 'blue')`
color: black;
`};
`;
<FnModsNotColorBlue color="black" />
color
is blue
or black
and is not undefined
export const FnModsColorBlueBlack = styled.div<{ color?: string }>`
${mods('color', ['blue', 'black'])`
color: black;
`};
`;
<FnModsColorBlueBlack color="black" />
color
is not blue
or black
and is not undefined
export const FnModsNotColorBlueBlack = styled.div<{ color?: string }>`
${mods.not('color', ['blue', 'black'])`
color: white;
`};
`;
<FnModsNotColorBlueBlack color="white" />
color
and bg
is not undefined
export const FnModsColorBg = styled.div<{ color?: string; bg?: string }>`
${mods(['color', 'bg'])`
color: black;
`};
`;
<FnModsColorBg color="black" bg="green" />
color
and bg
is undefined
export const FnModsNotColorBg = styled.div<{ color?: string; bg?: string }>`
${mods.not(['color', 'bg'])`
color: black;
`};
`;
<FnModsNotColorBg />
color
and bg
is blue
and is not undefined
export const FnModsColorBgBlue = styled.div<{ color?: string; bg?: string }>`
${mods(['color', 'bg'], 'blue')`
color: black;
`};
`;
<FnModsColorBgBlue color="blue" bg="blue" />
color
and bg
is not blue
and is not undefined
export const FnModsNotColorBgBlue = styled.div<{ color?: string; bg?: string }>`
${mods.not(['color', 'bg'], 'blue')`
color: black;
`};
`;
<FnModsNotColorBgBlue color="black" bg="green" />
color
and bg
together is blue
or green
and is not undefined
export const FnModsColorBgBlueGreen = styled.div<{
color?: string;
bg?: string;
}>`
${mods(['color', 'bg'], ['blue', 'green'])`
color: black;
`};
`;
<FnModsColorBgBlueGreen color="blue" bg="blue" />
color
and bg
together is not blue
or green
and is not undefined
export const FnModsNotColorBgBlueGreen = styled.div<{
color?: string;
bg?: string;
}>`
${mods.not(['color', 'bg'], ['blue', 'green'])`
color: black;
`};
`;
<FnModsNotColorBgBlueGreen color="blue" bg="green" />
Call as a literals
You can call any modifier, regardless of mode, as a literal and immediately pass the necessary styles.
Object mode
export const StyledComponent = styled.div<Mods<'size'>>`
${mods.size`
padding: 20px;
`};
${mods.size.small`
font-size: 14px;
`};
`;
<StyledComponent size="small" />
Function mode
export const StyledComponent = styled.div<Mods<'size'>`
${mods('size')`
font-size: 16px;
`};
${mods('size', 'small')`
font-size: 14px;
`};
`;
<StyledComponent size="small" />
Call as a function
You can call any modifier, regardless of mode, as a function that will return the css
method from styled-components
.
The feature of this method is that you get possible values and all the properties of the styled component in the arguments of the passed callback function.
Object mode
export const StyledComponent = styled.div<Mods<'size'> & { padding: string }>`
${mods.size(
(value, props) => css`
font-size: ${value === 'small' ? '14px' : '16px'};
padding: ${props.padding};
`
)};
${mods.size.small(
(value, props) => css`
font-size: 14px;
padding: ${props.padding};
`
)};
`;
<StyledComponent size="small" />
Function mode
export const StyledComponent = styled.div<Mods<'size'> & { padding: string }>`
${mods('size')(
(value, props) => css`
font-size: ${value === 'small' ? '14px' : '16px'};
padding: ${props.padding};
`
)};
${mods(
'size',
'small'
)(
(value, props) => css`
font-size: 14px;
padding: ${props.padding};
`
)};
`;
<StyledComponent size="small" />
:point_up: IMPORTANT:
If you use Function mode
, use modifiers from config
with type Mods
and pass an array of modifiers or an array of modifier values, be sure to put as const
after the array so that TypeScript correctly displays which properties will be available in the value
argument passed to the callback function.
For example:
const config = {
color: 'white' | 'blue' | 'black',
bg: 'green' | 'blue' | 'black',
...
};
export const StyledComponent = styled.div<Mods<'color' | 'bg'>>`
${mods('color', ['blue', 'black'] as const)(
(value, props) => css`
// value: 'blue' | 'black'
`
)};
${mods.not('color', ['blue', 'black'] as const)(
(value, props) => css`
// value: 'white'
`
)};
${mods(['color', 'bg'] as const)(
(value, props) => css`
// value: { color: 'white' | 'blue' | 'black', bg: 'green' | 'blue' | 'black' }
`
)};
${mods.not(['color', 'bg'] as const)(
(value, props) => css`
// value: { color: undefined, bg: undefined }
`
)};
${mods(['color', 'bg'] as const, 'blue')(
(value, props) => css`
// value: 'blue'
`
)};
${mods.not(['color', 'bg'] as const, 'blue')(
(value, props) => css`
// value: { color: 'white' | 'black', bg: 'green' | 'black' }
`
)};
${mods(['color', 'bg'] as const, ['blue', 'black'] as const)(
(value, props) => css`
// value: { color: 'blue' | 'black', bg: 'blue' | 'black' }
`
)};
${mods.not(['color', 'bg'] as const, ['blue', 'black'] as const)(
(value, props) => css`
// value: { color: 'white' | 'blue' | 'black', bg: 'green' | 'blue' | 'black' }
`
)};
`;
Using mixins
To apply a set of styles for different modifier values, you can create mixins.
const sizeMixin = (
spacing: RMods['spacing'],
fontSize: RMods['fontSize']
) => css`
padding: ${spacing}px;
font-size: ${fontSize}px;
`;
const StyledComponen = styled.div<Mods<'size'>>`
${mods.size.small(sizeMixin(12, 16))};
${mods.size.medium(sizeMixin(16, 20))};
${mods.size.large(sizeMixin(20, 24))};
`;
Additional features
You can use modifiers with boolean
values and pass them as string
and as boolean
:
export const StyledComponent = styled.div<Mods<'disabled'>>`
${mods.disabled.true`
color: gray;
`};
${mods('disabled', true)`
color: gray;
`};
${mods('disabled', 'true')`
color: gray;
`};
${mods.disabled.false`
color: black;
`};
${mods('disabled', false)`
color: black;
`};
${mods('disabled', 'false')`
color: black;
`};
`;
<StyledComponent disabled />
You can use modifiers with number
values:
export const StyledComponent = styled.div<Mods<'spacing'>>`
${mods.spacing[12]`
padding: 12px;
`};
${mods.spacing[24]`
padding: 24px;
`};
`;
<StyledComponent spacing={12} />
You can do any nesting
of modifiers:
export const StyledComponent = styled.div<Mods<'spacing' | 'size'>>`
${mods.size.small`
font-size: 14px;
`};
${mods.spacing[12]`
padding: 12px;
${mods.size.small`
font-size: 16px;
`};
`};
`;
<StyledComponent spacing={12} size="small" />
You can write additional logic
for processing modifier values:
export const StyledComponent = styled.div<{ src: string }>`
${mods('src')(
(value) => css`
color: ${value.includes('facebook') ? 'blue' : 'orange'};
`
)};
`;
<StyledComponent src='https://www.facebook.com/' />
<StyledComponent src='https://www.instagram.com/' />
Highlight syntax
In order to make syntax highlighting in the IDE, you need to install the styled-components plugin.
In most of the plugins for styled-components it is possible to add a keyword in relation to which the syntax highlighting will be performed.
For example, plugin for IDE WebStorm.
After installing the plugin, go to WebStorm/Preferences/Languages & Frameworks/JavaScript/Styled Components
,
click on +
and add the keyword mods
.
After that, the CSS syntax will be highlighted in the styles defined in mods
.
Editor Plugins
VS Code
- Syntax Highlighting - language-babel
- Autocompletion - vscode-styled-components
- Linting - stylelint
WebStorm
- Syntax Highlighting & Autocompletion - webstorm-styled-components
Atom
- Syntax Highlighting and Autocompletion - language-babel
Sublime Text
- Syntax Highlighting & Autocompletion - Naomi, JSCustom ( refer to document on how to turn on Styled Component syntax)
- Linting - SublimeLinter-stylelint, LSP Stylelint