├── .gitignore ├── package.json ├── LICENSE ├── index.js ├── scripts ├── defaultOptions.js └── buttons.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss-base-buttons", 3 | "version": "1.0.1", 4 | "description": "A base button styling for Tailwind Css", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/thebakerdev/tailwindcss-base-buttons.git" 12 | }, 13 | "keywords": [ 14 | "tailwindcss", 15 | "tailwindcss-plugin", 16 | "buttons" 17 | ], 18 | "author": "Marc Tallo", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/thebakerdev/tailwindcss-base-buttons/issues" 22 | }, 23 | "homepage": "https://github.com/thebakerdev/tailwindcss-base-buttons#readme", 24 | "dependencies": { 25 | "color": "^3.1.2", 26 | "lodash": "^4.17.20" 27 | }, 28 | "devDependencies": { 29 | "tailwindcss": "^1.8.10" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Marc Tallo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const Color = require('color'); 3 | const buttons = require('./scripts/buttons'); 4 | const defaultOptions = require('./scripts/defaultOptions'); 5 | 6 | /* Sets a color config object from the options */ 7 | function setColorConfig(options) { 8 | 9 | const colorConfig = _.omit({ 10 | ..._.isFunction(options.colors.default) ? options.colors.default() : options.colors.default, 11 | ..._.isFunction(options.colors.theme) ? options.colors.theme() : options.colors.theme 12 | }); 13 | 14 | return colorConfig; 15 | } 16 | 17 | /* Combines all button styles */ 18 | function combineStyles(colorConfig, options, custom) { 19 | 20 | let customStyles = {}; 21 | 22 | if (typeof custom === 'function') { 23 | 24 | customStyles = custom(colorConfig, options); 25 | } else if (typeof custom === 'object') { 26 | 27 | customStyles = custom; 28 | } 29 | 30 | return { 31 | ...buttons.createDefault(options), 32 | ...buttons.createRounded(options), 33 | ...buttons.createSolid(colorConfig, options), 34 | ...buttons.createOutlined(colorConfig, options), 35 | ...buttons.createGradient(colorConfig, options), 36 | ...customStyles 37 | } 38 | } 39 | 40 | module.exports = function(options, custom) { 41 | 42 | options = _.isFunction(options) ? defaultOptions() : _.defaultsDeep(options, defaultOptions()); 43 | 44 | const colorConfig = setColorConfig(options); 45 | 46 | const buttonStyles = combineStyles(colorConfig, options, custom); 47 | 48 | const buttonSizes = buttons.createSizes(options); 49 | 50 | return function({ addComponents }) { 51 | 52 | addComponents([ 53 | buttonStyles, 54 | buttonSizes 55 | ]); 56 | } 57 | } -------------------------------------------------------------------------------- /scripts/defaultOptions.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const defaultConfig = require('tailwindcss/defaultConfig'); 3 | 4 | const colors = require('tailwindcss/colors') 5 | const defaultColors = _.omit(colors, [ 6 | 'transparent', 7 | 'current' 8 | ]); 9 | 10 | /* Sets default colors options from Tailwindcss' config */ 11 | function setDefaultColorOptions() { 12 | 13 | const colorOptions = {}; 14 | 15 | const override = { 16 | black: { 17 | background: defaultColors['black'], 18 | text: defaultColors['white'] 19 | }, 20 | white: { 21 | background: defaultColors['white'], 22 | text: defaultColors['black'] 23 | } 24 | } 25 | 26 | _.forIn(defaultColors, (value, key) => { 27 | 28 | colorOptions[key] = { 29 | background: _.get(override[key], 'background', value[500]), 30 | text: _.get(override[key], 'text', defaultColors['white']) 31 | }; 32 | }); 33 | 34 | return colorOptions; 35 | } 36 | 37 | /* Sets the default theme colors */ 38 | function setDefaultThemeColors() { 39 | 40 | return { 41 | primary: { 42 | background: defaultColors['blue'][500], 43 | text: defaultColors['white'] 44 | }, 45 | secondary: { 46 | background: defaultColors['teal'][500], 47 | text: defaultColors['white'] 48 | }, 49 | danger: { 50 | background: defaultColors['red'][500], 51 | text: defaultColors['white'] 52 | }, 53 | default: { 54 | background: '#e0e1e2', 55 | text: defaultColors['gray'][700], 56 | hoverText: defaultColors['gray'][700], 57 | activeText: defaultColors['gray'][700] 58 | }, 59 | disabled: { 60 | background: '#e0e1e2', 61 | cursor: 'default', 62 | hoverBackground: '#e0e1e2', 63 | hoverText: defaultColors['gray'][700], 64 | opacity: '.45', 65 | pointerEvents: 'none', 66 | text: defaultColors['gray'][700] 67 | } 68 | } 69 | } 70 | 71 | module.exports = function() { 72 | return { 73 | baseClass: '.btn', 74 | borderRadius: '.25rem', 75 | borderWidth: '1', 76 | colors: { 77 | default: setDefaultColorOptions, 78 | theme: setDefaultThemeColors 79 | }, 80 | cursor: 'pointer', 81 | fontSize: '1rem', 82 | fontWeight: '500', 83 | lineHeight: '1.25', 84 | padding: '.75em 1.5em', 85 | sizes: { 86 | xs: { 87 | fontSize: '0.75rem', 88 | padding: '0.5625rem 1.125rem' 89 | }, 90 | sm: { 91 | fontSize: '0.875rem', 92 | padding: '0.65625rem 1.3125rem' 93 | }, 94 | md: { 95 | fontSize: '1rem', 96 | padding: '.75em 1.5em', 97 | }, 98 | lg: { 99 | fontSize: '1.125rem', 100 | padding: '0.84375rem 1.6875rem' 101 | }, 102 | xl: { 103 | fontSize: '1.25rem', 104 | padding: '0.9525rem 1.905rem' 105 | } 106 | }, 107 | transition: 'all .2s ease-out' 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tailwind CSS Base Buttons 2 | This plugin adds a bunch of base button classes in your Tailwindcss components which can be customized based on your theme colors. 3 | 4 | Demo & Documentation 5 | 6 | ## Install 7 | 1. Install the plugin: 8 | ``` 9 | npm install tailwindcss-base-buttons --save-dev 10 | ``` 11 | 2. Add it inside your `tailwind.config.js` file: 12 | ``` 13 | module.exports = { 14 | // ... 15 | plugins: [ 16 | require('tailwindcss-base-buttons')() 17 | ] 18 | } 19 | ``` 20 | ## Documentation 21 | Out of the box, the plugin will generate these classes for styling your buttons. 22 | - `btn-{color}` - Colors are the default Tailwind colors. Ex: `btn-indigo`. 23 | - `btn-{theme}` - These classes are theme based colors. Ex: `btn-primary`. Other options are `secondary`, `danger`, `default` & `disabled`. 24 | - `btn-outlined-{color|theme}` - These are outlined button based on default and theme colors. Ex: `btn-outlined-primary` or `btn-outlined-red`. 25 | - `btn-outlined-alt-{color|theme}` - Same as outlined button but with solid backround on hover. 26 | - `btn-gradient-{color|theme}` -These are gradient buttons based on default and theme colors. Ex: `btn-gradient-primary` or `btn-gradient-pink`. 27 | - `btn-{size}` - These are button size classes. Ex: `btn-xs`. Other options are `sm`,`md`(default), `lg`,`xl`, 28 | - `btn-rounded` - These makes rounded buttons 29 | 30 | ## Customization 31 | The appearance of the button can be customized by passing an option object as a first argument of the plugin. Ex: 32 | ``` 33 | module.exports = { 34 | // ... 35 | plugins: [ 36 | require('tailwindcss-base-buttons')({ 37 | baseClass: '.button', 38 | borderRadius: '.5rem', 39 | padding: '.5rem 1rem', 40 | colors: { 41 | theme: { 42 | primary: { 43 | background: red, 44 | text: white 45 | }, 46 | secondary: { 47 | background: blue, 48 | text: black 49 | } 50 | } 51 | } 52 | }) 53 | ] 54 | } 55 | 56 | ``` 57 | The example above will generate classes like `.button-*` with border-radius `.5rem` and padding `.5rem 1rem`. The theme colors generated would be `.button-primary` & `.button-secondary`. 58 | 59 | You can also add your custom button styles by adding an object or a callback that generates your button style object as a second argument. 60 | Ex: using an object. This adds the `.btn-sample` class 61 | ``` 62 | module.exports = { 63 | // ... 64 | plugins: [ 65 | require('tailwindcss-base-buttons')({ 66 | baseClass: '.btn' 67 | },{ 68 | '.btn-sample': { 69 | color: 'red', 70 | width: '200px' 71 | } 72 | }) 73 | ] 74 | } 75 | ``` 76 | Ex: using a callback. By using a callback, you can access the `colorConfig` and `options` which contains the default and theme colors and the options. This will add `.btn-sample-{color|theme}` classes. 77 | ``` 78 | module.exports = { 79 | // ... 80 | plugins: [ 81 | require('tailwindcss-base-buttons')({ 82 | baseClass: '.btn' 83 | },(colorConfig, options) => { 84 | 85 | let additionalStyles = {}; 86 | 87 | Object.entries(colorConfig, config => { 88 | 89 | let [key, properties] = config; 90 | 91 | Object.assign(additionalStyles, { 92 | [`${options.baseClass}-sample-${key}`]: { 93 | backgroundColor: properties['background'], 94 | width: '200px' 95 | } 96 | }) 97 | }); 98 | 99 | return additionalStyles; 100 | }) 101 | ] 102 | } 103 | ``` 104 | 105 | 106 | -------------------------------------------------------------------------------- /scripts/buttons.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const Color = require('color'); 3 | 4 | /* Creates default button */ 5 | const createDefault = options => { 6 | 7 | return { 8 | [`${options.baseClass}`]: { 9 | borderRadius: options.borderRadius, 10 | cursor: options.cursor, 11 | display: 'inline-block', 12 | fontSize: options.fontSize, 13 | fontWeight: options.fontWeight, 14 | lineHeight: options.lineHeight, 15 | padding: options.padding, 16 | textDecoration: 'none', 17 | transition: options.transition 18 | } 19 | } 20 | } 21 | 22 | /* Creates solid colored buttons */ 23 | const createSolid = (colorConfig, options) => { 24 | 25 | if (_.isEmpty(colorConfig)) return {}; 26 | 27 | let buttonStyles = {}; 28 | 29 | _.forIn(Object.entries(colorConfig), config => { 30 | 31 | let [key, properties] = config; 32 | 33 | Object.assign(buttonStyles, { 34 | [`${options.baseClass}-${key}`]: { 35 | backgroundColor: properties['background'], 36 | color: properties['text'], 37 | cursor: _.get(properties, 'cursor', options.cursor), 38 | opacity: _.get(properties, 'opacity', '1'), 39 | pointerEvents: _.get(properties, 'pointerEvents', 'auto'), 40 | '&:hover': { 41 | backgroundColor: _.get(properties, 'hoverBackground', Color(properties.background).darken(0.1).hex().toString()), 42 | color: _.get(properties, 'hoverText', properties.text) 43 | }, 44 | '&:active': { 45 | backgroundColor: _.get(properties, 'activeBackground', Color(properties.background).darken(0.1).hex().toString()), 46 | color: _.get(properties, 'activeText', properties.text) 47 | } 48 | } 49 | }); 50 | }); 51 | 52 | return buttonStyles; 53 | } 54 | 55 | /* Creates outlined buttons */ 56 | const createOutlined = (colorConfig, options) => { 57 | 58 | if (_.isEmpty(colorConfig)) return {}; 59 | 60 | let buttonStyles = {}; 61 | 62 | _.forIn(Object.entries(colorConfig), config => { 63 | 64 | let [key, properties] = config; 65 | 66 | let textColor = (key === 'default' || key === 'disabled') ? `${properties.text}` : `${properties.background}`; 67 | 68 | let buttonProperties = { 69 | backgroundColor: 'transparent', 70 | border: `solid ${options.borderWidth}px ${properties.background}`, 71 | color: textColor, 72 | cursor: _.get(properties, 'cursor', options.cursor), 73 | opacity: _.get(properties, 'opacity', '1'), 74 | pointerEvents: _.get(properties, 'pointerEvents', 'auto'), 75 | }; 76 | 77 | Object.assign(buttonStyles, { 78 | [`${options.baseClass}-outlined-${key}`]: { 79 | ...buttonProperties, 80 | '&:hover': { 81 | borderColor: _.get(properties, 'hoverBorderColor', Color(properties.background).darken(0.2).hex().toString()), 82 | borderWidth: _.get(properties, 'hoverBorderWidth', options.borderWidth), 83 | color: _.get(properties, 'hoverText', textColor) 84 | }, 85 | '&:active': { 86 | borderColor: _.get(properties, 'activeBorderColor', Color(properties.background).darken(0.2).hex().toString()), 87 | borderWidth: _.get(properties, 'activeBorderWidth', options.borderWidth), 88 | color: _.get(properties, 'activeText', textColor) 89 | } 90 | } 91 | }, 92 | { 93 | [`${options.baseClass}-outlined-alt-${key}`]: { 94 | ...buttonProperties, 95 | '&:hover': { 96 | backgroundColor: _.get(properties, 'hoverBackground', properties.background), 97 | color: _.get(properties, 'hoverText', '#fff') 98 | }, 99 | '&:active': { 100 | borderColor: _.get(properties, 'hoverBorderColor', properties.background), 101 | color: _.get(properties, 'activeText', '#fff') 102 | } 103 | } 104 | }); 105 | }); 106 | 107 | return buttonStyles; 108 | } 109 | 110 | /* Creates rounded buttons */ 111 | function createRounded(options) { 112 | return { 113 | [`${options.baseClass}-rounded`] : { 114 | borderRadius: '25px' 115 | }, 116 | } 117 | } 118 | 119 | /* Creates gradient buttons */ 120 | function createGradient(colorConfig, options) { 121 | 122 | if (_.isEmpty(colorConfig)) return {}; 123 | 124 | let buttonStyles = {}; 125 | 126 | _.forIn(Object.entries(colorConfig), config => { 127 | 128 | let [key, properties] = config; 129 | 130 | let dark = Color(properties.background).darken(0.2).hex().toString(); 131 | 132 | let light = Color(properties.background).lighten(0.1).hex().toString(); 133 | 134 | Object.assign(buttonStyles, { 135 | [`${options.baseClass}-gradient-${key}`]: { 136 | backgroundImage: `linear-gradient(to right, ${dark} 0%, ${light} 51%, ${dark} 100%)`, 137 | backgroundSize: '200% auto', 138 | color: '#fff', 139 | '&:hover': { 140 | backgroundPosition: 'right center' 141 | } 142 | } 143 | }); 144 | }); 145 | 146 | return buttonStyles; 147 | } 148 | 149 | /* Creates button sizes */ 150 | function createSizes(options) { 151 | 152 | let buttonSizes = {}; 153 | 154 | Object.entries(options.sizes).forEach(size => { 155 | 156 | let [key, properties] = size; 157 | 158 | Object.assign(buttonSizes, { 159 | [`${options.baseClass}-${key}`]: { 160 | fontSize: properties.fontSize, 161 | padding: properties.padding 162 | } 163 | }) 164 | }); 165 | 166 | return buttonSizes; 167 | } 168 | 169 | module.exports = { 170 | createDefault, 171 | createSolid, 172 | createOutlined, 173 | createRounded, 174 | createGradient, 175 | createSizes 176 | } --------------------------------------------------------------------------------