-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature Proposal] Coloured Box Shadow #654
Comments
You can already generate all the box shadow utilities you need with the
Do you mean that you would like Tailwind to automatically generate shadow utilities based on the
|
Yeah, I guess |
Going to close this as not something I plan to add to the default config out of the box right now, but of course can add in your own config 👍 Can definitely see a use case for things like focus styles on different colored buttons for example. |
As another person who reached for/wished for this functionality today, is it possible to generate color shadows based on the base box-shadow sizes determined by choice (rather than automatically)? Could boxShadow be extended with a colors section where users could set a range box-shadow colors in reference to the main theme colors (or something similar), with boxShadow sizing being handled separately? I.e shadow-xl-blue would be generated if the boxShadow config was extended with the color blue. For me personally, this would be more maintainable than hardcoding the rgba values into boxShadows as is currently done in the config. Currently assuming that users will only use black shadows seems limiting to me |
What should I add in my config to get this? I am looking for a coloured version of my own shadow |
Update: If you find this thread, here is how the config should look: module.exports = {
theme: {
extend: {
boxShadow: {
blue: '0 4px 14px 0 rgba(19, 51, 81, 0.39)',
},
},
},
}; And then you can use it with |
Here's an example of adding all shadow variants for all colors in the new Tailwind UI:
|
that will allow you to use |
Thanks for the workarounds. I agree this should be in core. |
This should be in core. |
Building on top of this, this is what I did. {
boxShadow: theme => ({
xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
none: 'none',
// Build on top of our existing colors
...Object.entries(theme('colors'))
.map(([key, value]) => makeShadow(key, value))
.reduce((acc, cur) => ({ ...acc, ...cur }), {}),
}),
} |
@cerino-ligutom Only works with strings. ie: I see what you're doing though and might be able to get it working with objs as well. My solution with objs as well: const hexRgb = require('hex-rgb') // yarn add hex-rgb
const defaultTheme = require('tailwindcss/defaultTheme')
// https://github.com/tailwindcss/tailwindcss/issues/654#issuecomment-606746700
const makeShadow = (name, rgb) => {
const obj = {}
obj[`${name}-xs`] = `0 0 0 1px rgba(${rgb}, 0.05)`
obj[`${name}-xs`] = `0 0 0 1px rgba(${rgb}, 0.05)`
obj[`${name}-sm`] = `0 1px 2px 0 rgba(${rgb}, 0.05)`
obj[name] = `0 1px 3px 0 rgba(${rgb}, 0.1), 0 1px 2px 0 rgba(${rgb}, 0.06)`
obj[`${name}-md`] = `0 4px 6px -1px rgba(${rgb}, 0.1), 0 2px 4px -1px rgba(${rgb}, 0.06)`
obj[`${name}-lg`] = `0 10px 15px -3px rgba(${rgb}, 0.1), 0 4px 6px -2px rgba(${rgb}, 0.05)`
obj[`${name}-xl`] = `0 20px 25px -5px rgba(${rgb}, 0.1), 0 10px 10px -5px rgba(${rgb}, 0.04)`
obj[`${name}-2xl`] = `0 25px 50px -12px rgba(${rgb}, 0.25)`
obj[`${name}-inner`] = `inset 0 2px 4px 0 rgba(${rgb}, 0.06)`
return obj
}
module.exports = {
theme: {
colors: {
...defaultTheme.colors,
// Custom
primary: {
100: '#d2e1ed',
200: '#a5c4dc',
300: '#78a6ca',
400: '#4b89b9',
500: '#1e6ba7',
600: '#185686',
700: '#124064',
800: '#0c2b43',
900: '#061521',
},
font: {
100: '#d6d7d7',
200: '#adb0b0',
300: '#848888',
400: '#5b6161',
500: '#323939',
600: '#282e2e',
700: '#1e2222',
800: '#141717',
900: '#0a0b0b',
},
danger: {
100: '#ffd8d6',
200: '#ffb1ac',
300: '#fe8983',
400: '#fe6259',
500: '#fe3b30',
600: '#cb2f26',
700: '#98231d',
800: '#661813',
900: '#330c0a',
},
},
// https://github.com/tailwindcss/tailwindcss/issues/654#issuecomment-619279397
boxShadow: theme => {
// Handle color objects as well
const fresh = Object.values(
Object.entries(theme('colors')).reduce((acc, curr) => {
const [k, v] = curr
if (typeof v === 'string' && v !== 'transparent' && v !== 'currentColor') {
const { red, green, blue } = hexRgb(v)
acc[k] = makeShadow(k, `${red}, ${green}, ${blue}`)
}
if (typeof v === 'object') {
Object.entries(v).forEach(([_k, _v]) => {
const { red, green, blue } = hexRgb(_v)
acc[`${k}-${_k}`] = makeShadow(
`${k}-${_k}`,
`${red}, ${green}, ${blue}`,
)
})
}
return acc
}, {}),
).reduce((acc, cur) => ({ ...acc, ...cur }), {})
return {
xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
none: 'none',
...fresh,
}
},
},
} Produces shadows like: .md\:shadow-shadow-primary-100-sm {
box-shadow: 0 1px 2px 0 rgba(210, 225, 237, 0.05);
} |
Based on @corysimmons solution but removing the black shadow boilerplate code and dependency to and external hexToRgb package : const colors = require('tailwindcss/colors')
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result
? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16),
}
: null
}
function makeShadow(name, rgb) {
const obj = {}
const nameWithDash = name ? `${name}-`: ''
const defaultName = name ? name : 'DEFAULT'
obj[`${nameWithDash}xs`] = `0 0 0 1px rgba(${rgb}, 0.05)`
obj[`${nameWithDash}sm`] = `0 1px 2px 0 rgba(${rgb}, 0.05)`
obj[defaultName] = `0 1px 3px 0 rgba(${rgb}, 0.1), 0 1px 2px 0 rgba(${rgb}, 0.06)`
obj[`${nameWithDash}md`] = `0 4px 6px -1px rgba(${rgb}, 0.1), 0 2px 4px -1px rgba(${rgb}, 0.06)`
obj[`${nameWithDash}lg`] = `0 10px 15px -3px rgba(${rgb}, 0.1), 0 4px 6px -2px rgba(${rgb}, 0.05)`
obj[`${nameWithDash}xl`] = `0 20px 25px -5px rgba(${rgb}, 0.1), 0 10px 10px -5px rgba(${rgb}, 0.04)`
obj[`${nameWithDash}2xl`] = `0 25px 50px -12px rgba(${rgb}, 0.25)`
obj[`${nameWithDash}inner`] = `inset 0 2px 4px 0 rgba(${rgb}, 0.06)`
return obj
}
function buildShadowPalette(theme) {
// default tailwindcss black shadows
const defaultPalette = {
...makeShadow('', '0, 0, 0'),
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
none: 'none'
}
const coloredShadowPalette = Object.values(
Object.entries(theme('colors')).reduce((acc, curr) => {
const [k, v] = curr
if (typeof v === 'string' && v !== 'transparent' && v !== 'currentColor') {
const { red, green, blue } = hexToRgb(v)
acc[k] = makeShadow(k, `${red}, ${green}, ${blue}`)
}
if (typeof v === 'object') {
Object.entries(v).forEach(([_k, _v]) => {
const { red, green, blue } = hexToRgb(_v)
acc[`${k}-${_k}`] = makeShadow(
`${k}-${_k}`,
`${red}, ${green}, ${blue}`,
)
})
}
return acc
}, {})
)
return coloredShadowPalette.reduce((acc, cur) => ({ ...acc, ...cur }), defaultPalette)
}
module.exports = {
theme: {
colors: {
primary: colors.teal,
neutral: colors.coolGray,
info: colors.blue,
success: colors.emerald,
warning: colors.amber,
danger: colors.rose
},
boxShadow: (theme) => {
return {
...buildShadowPalette(theme),
}
},
},
variants: {},
plugins: [],
} |
@fabien-ml Your snippet is awesome! Just a little improvement because it threw an exception for me: const colors = require('tailwindcss/colors')
function hexToRgb(hex) {
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function (m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result
? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16),
}
: null
}
function makeShadow(name, rgb) {
const obj = {}
const nameWithDash = name ? `${name}-`: ''
const defaultName = name ? name : 'DEFAULT'
obj[`${nameWithDash}xs`] = `0 0 0 1px rgba(${rgb}, 0.05)`
obj[`${nameWithDash}sm`] = `0 1px 2px 0 rgba(${rgb}, 0.05)`
obj[defaultName] = `0 1px 3px 0 rgba(${rgb}, 0.1), 0 1px 2px 0 rgba(${rgb}, 0.06)`
obj[`${nameWithDash}md`] = `0 4px 6px -1px rgba(${rgb}, 0.1), 0 2px 4px -1px rgba(${rgb}, 0.06)`
obj[`${nameWithDash}lg`] = `0 10px 15px -3px rgba(${rgb}, 0.1), 0 4px 6px -2px rgba(${rgb}, 0.05)`
obj[`${nameWithDash}xl`] = `0 20px 25px -5px rgba(${rgb}, 0.1), 0 10px 10px -5px rgba(${rgb}, 0.04)`
obj[`${nameWithDash}2xl`] = `0 25px 50px -12px rgba(${rgb}, 0.25)`
obj[`${nameWithDash}inner`] = `inset 0 2px 4px 0 rgba(${rgb}, 0.06)`
return obj
}
function buildShadowPalette(theme) {
// default tailwindcss black shadows
const defaultPalette = {
...makeShadow('', '0, 0, 0'),
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
none: 'none'
}
const coloredShadowPalette = Object.values(
Object.entries(theme('colors')).reduce((acc, curr) => {
const [k, v] = curr
if (typeof v === 'string' && v !== 'transparent' && v !== 'currentColor') {
const { red, green, blue } = hexToRgb(v)
acc[k] = makeShadow(k, `${red}, ${green}, ${blue}`)
}
if (typeof v === 'object') {
Object.entries(v).forEach(([_k, _v]) => {
const { red, green, blue } = hexToRgb(_v)
acc[`${k}-${_k}`] = makeShadow(
`${k}-${_k}`,
`${red}, ${green}, ${blue}`,
)
})
}
return acc
}, {})
)
return coloredShadowPalette.reduce((acc, cur) => ({ ...acc, ...cur }), defaultPalette)
}
module.exports = {
theme: {
colors: {
primary: colors.teal,
neutral: colors.coolGray,
info: colors.blue,
success: colors.emerald,
warning: colors.amber,
danger: colors.rose
},
boxShadow: (theme) => {
return {
...buildShadowPalette(theme),
}
},
},
variants: {},
plugins: [],
} To ensure that all the 3 letter hex codes are converted properly. |
Thanks for this! Used it to create a custom plugin:
And in the tailwind.config.js file, add:
|
This should be part of the core. P.s.: Just started to play around with TW, but so far, I think I will use it in future projects.
This was your closure comment over a year ago. Still not considering to add it? |
This also now needs to handle triplets like Updated: // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb/19765382
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16)
} : null;
} Thanks for the solution @isMandyCoding! So helpful :) |
I'd to combine @isMandyCoding 's plugin with @jwbaldwin 's converter to create this. This code works fine for me. // shadowpaletteplugin.js
const plugin = require('tailwindcss/plugin')
// https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb/19765382
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
hex = hex.replace(shorthandRegex, function (m, r, g, b) {
return r + r + g + g + b + b
})
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result
? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16)
}
: null
}
function makeShadow(name, rgb) {
const obj = {}
const slicedName = name.includes('DEFAULT') ? name.slice(0, name.indexOf('-DEFAULT')) : name
const nameWithDash = slicedName ? `${slicedName}-` : ''
obj[`.shadow-${nameWithDash}xs`] = {
boxShadow: `0 0 0 1px rgba(${rgb}, 0.05)`
}
obj[`.shadow-${nameWithDash}sm`] = {
boxShadow: `0 1px 2px 0 rgba(${rgb}, 0.05)`
}
obj[`.shadow-${nameWithDash}md`] = {
boxShadow: `0 4px 6px -1px rgba(${rgb}, 0.1), 0 2px 4px -1px rgba(${rgb}, 0.06)`
}
obj[`.shadow-${nameWithDash}lg`] = {
boxShadow: `0 10px 15px -3px rgba(${rgb}, 0.1), 0 4px 6px -2px rgba(${rgb}, 0.05)`
}
obj[`.shadow-${nameWithDash}xl`] = {
boxShadow: `0 20px 25px -5px rgba(${rgb}, 0.1), 0 10px 10px -5px rgba(${rgb}, 0.04)`
}
obj[`.shadow-${nameWithDash}2xl`] = {
boxShadow: `0 25px 50px -12px rgba(${rgb}, 0.25)`
}
obj[`.shadow-${nameWithDash}3xl`] = {
boxShadow: `0 0 8px 0 rgba(${rgb}, 0.5)`
}
obj[`.shadow-${nameWithDash}inner`] = {
boxShadow: `inset 0 2px 4px 0 rgba(${rgb}, 0.06)`
}
return obj
}
function buildShadowPalette(theme) {
const coloredShadowPalette = Object.values(
Object.entries(theme('colors')).reduce((acc, curr) => {
const [k, v] = curr
if (typeof v === 'string' && v !== 'transparent' && v !== 'currentColor') {
const { red, green, blue } = hexToRgb(v)
acc[k] = makeShadow(k, `${red}, ${green}, ${blue}`)
}
if (typeof v === 'object') {
Object.entries(v).forEach(([_k, _v]) => {
const { red, green, blue } = hexToRgb(_v)
acc[`${k}-${_k}`] = makeShadow(`${k}-${_k}`, `${red}, ${green}, ${blue}`)
})
}
return acc
}, {})
)
return coloredShadowPalette.reduce((acc, cur) => ({ ...acc, ...cur }), {})
}
module.exports = plugin(function ({ theme, addUtilities, variants }) {
addUtilities([buildShadowPalette(theme)], {
variants: [...variants('boxShadow'), 'active']
})
})
Although this works as expected, but shadows like Thanks Everyone! |
Is this possible with JIT mode without requiring the plugin? Edit: It's not possible. I went with 1 custom property hah 🎃 #nprogress .peg {
box-shadow: 0 0 20px rebeccapurple, 0 0 15px rebeccapurple;
@apply block absolute right-0 w-[140px] h-full opacity-100 rotate-3 translate-x-0 -translate-y-1;
} |
I've started prototyping support for colored shadows and am hoping it makes it into v3 in the fall. |
@adamwathan |
Yep it's not an easy problem to solve, agree with all the concerns you've presented. Hoping we find a clever approach that makes it feel useful but only a few weeks of R&D will say for sure. |
Found this thread while looking for this feature. Something nice to have and would definitely increase the ground with tailwind. |
A possible alternative, using whatever colour-to-rgb function you want. I haven't used it much (tested on v2 with jit), may have downsides (Use like In theme object:
Plugin (note: depending on your rgb function, will need to handle invalid colour entries by returning early)
For default colours, can set a base variable in css file or alternately in the box shadow properties themselves like
|
Oh amazing! Thanks for the heads up |
Heya,
I think it'd be neat if box shadows worked with colour variations. I tried to reach for it for a hover state and really wished it was there.
The text was updated successfully, but these errors were encountered: