Color Pallet Dropdown
A common use case for a custom dropdown is to present a Pallet of colors. Clicking a color then updates the styling of some user element.
Examples
Two examples are presented which illustrate a drop down menu with a grid of color swatches. For illustration purposes we are using Tailwind’s color families.
The first example uses the ClickDropdownMenu_A parent component to wrap a custom PalletGrid component. The code block used to present this example is listed to follow.
---import PalletGrid from '/components/PalletGrid.astro'import ClickDropdownMenu_A from '/components/ClickDropdownMenu_A.astro'const tw = { icon:'inline-block size-6', button:'colorPallet bg-gray-200 border-2 border-gray-600 dark:bg-gray-700 size-16'}---<ClickDropdownMenu_A id='click-activated-pallet' moveXY='-200,18' buttonStyles={tw.button} duration='180ms'> <img slot="leftIcon" src='/images/tailwind_icon.svg' alt='tailwind icon' class={tw.icon}/> <PalletGrid hs="on click send closeDropdown to the .colorPallet then settle then alert( 'You selected ' + my @title)"/></ClickDropdownMenu_A>The second example creates the vertically oriented pallet (for small screens) with hover activation. This example is built with the HoverDropdownMenu_B component outlined earlier.
The code block used to embed the hover activated pallet is shown following the example.
---import PalletGrid from '/components/PalletGrid.astro'import HoverDropdownMenu_B from '/components/HoverDropdownMenu_B.astro'const tw = { icon:'inline-block size-6', button:'colorPallet bg-gray-200 border-2 border-gray-600 dark:bg-gray-700 size-16'}---<HoverDropdownMenu_B id='hover-activated-pallet' moveXY='-200,18' buttonStyles={tw.button} duration='180ms'> <img slot="leftIcon" src='/images/tailwind_icon.svg' alt='tailwind icon' class={tw.icon}/> <PalletGrid orientation='vertical' hs="on click send closeDropdown to the .colorPallet then settle then alert( 'You selected ' + my @title)"/></HoverDropdownMenu_B>Description
This hyperComponent utilizes either the ClickDropdownMenu_A or HoverDropdownMenu_B parent components presented in earlier.
The default slot for the dropdown component(s) receives a PalletGrid custom component. The PalletGrid takes an orientation prop which returns either a horizontally or vertically oriented grid of color swatches.
Each swatch is comprised of a PalletItem component which accepts a twColor and hexCode prop. The twColor is the Tailwind color class and the hexCode is the equivalent hexadecimal value of the color.
Features
-The trigger button does not receive acaption prop so the dropdown’s appearance is only indicated by its icon.
-The Tailwind logo icon is passed into the leftIcon slot with appropriate styling classes applied.
-The duration prop is set to ‘180ms’ but can be any value.
-Hovering over an individual swatch reveals a tooltip displaying the Tailwind color family, shade, and corresponding hex value.
-Clicking a swatch dismisses the dropdown smoothly and then displays an alert showing the color name and hexidecimal value of the selection.
-A class of .colorPallet is added to the buttonStyles prop of the parent component so that the Hyperscript associated with each swatch can send a custom event which triggers closure of the dropdown after a selection is made.
The dropdown is dismissed by:
1. Tapping the trigger button again
2. Clicking outside the dropdown
3. Mouse leaving the dropdown
4. Tapping any color swatch
5. Pressing the Escape key when the trigger button is focused
In the hover activated example, a Hyperscript behavior (ToggleDropwon) is installed into the <button>from a <script> tag in the HoverDropdownMenu_B component. This behavior adds tracking of the mouseenter and mouseleave system events in order to set dropdown visibility based on hover state.
Components
PalletGrid
This component is passed into the default slot of each dropdown parent component. The PalletGrid takes an orientation prop. The default orientation is horizontal. In the horizontal orientation a total of 22 Tailwind color families are placed into columns across a grid layout with the corresponding shade values in each row. In the vertical orientation, an 11 column grid is used to display the color shades across the columns with the corresponding color families in each row.
Here is the code for the PalletGrid component. The horizontal and vertical pallets are imported and a JSX style ternary expression used to decide which orientation is returned depending on the value of the orientation prop.
---import PalletGridH from "/components/PalletGridH.astro"import PalletGridV from "/components/PalletGridV.astro"
interface Props { orientation?:string hs?:string}
const {orientation = "horizontal", hs} = Astro.props---
<div > {orientation === 'horizontal' ? <PalletGridH hs={hs}/> : <PalletGridV hs={hs}/>}</div>PalletGridH (horizontal)
Here is the code for the horizontal pallet variant. The data for each color family and shade are contained in separate arrays. A JSX expression in the component markup loops the two arrays to build the grid of swatches.
The horizontal dropdown displays 22 columns with each column representing one of the Tailwind color families and the rows representing the shading values.
Since the Tailwind library does not offer a ‘grid-cols-22’ utility class and ‘grid-cols-[22]’ did not work, a style attribute was added to the grid container to specify a 22 column layout.
--- import PalletItem from '/components/PalletItem.astro';
interface Props { hs?: string }
const {hs} = Astro.props
const tw = { grid: 'grid grid-rows-1 gap-2 px-4', palletContainer: 'mt-0 flex flex-col gap-y-2', }
const colorFamilies = ['slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'] const shades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] const hexValues = [ ['f8fafc', 'f9fafb', 'fafafa', 'fafafa', 'fafaf9', 'fef2f2', 'fff7ed', 'fffbeb', 'fefce8', 'f7fee7', 'f0fdf4', 'ecfdf5', 'f0fdfa', 'ecfeff', 'f0f9ff', 'eff6ff', 'eef2ff', 'f5f3ff', 'faf5ff', 'fdf4ff', 'fdf2f8', 'fff1f2'], //50, ['f1f5f9', 'f3f4f6', 'f4f4f5', 'f5f5f5', 'f5f5f4', 'fee2e2', 'ffedd5', 'fefec7', 'fef9c3', 'ecfccb', 'dcfce7', 'd1fae5', 'ccfbf1', 'cffafe, e0f2fe', 'dbeafe', 'e0e7ff', 'ede9fe', 'f3e8ff', 'fae8ff', 'fce7f3', 'ffe4e6'], //100 ['e2e8f0', 'e5e7eb', 'e4e4e7', 'e5e5e5', 'e7e5e4', 'fecaca', 'fed7aa', 'fde68a', 'fef08a', 'd9f99d', 'bbf7d0', 'a7f3d0', '99f6e4', 'a5f3fc', 'bae6fd', 'bfdbfe', 'c7d2fe', 'ddd6fe', 'e9d5ff', 'f5d0fe', 'fbcfe8', 'fecdd3'], //200 ['cbd5e1', 'd1d5db', 'd4d4d8', 'd4d4d4', 'd6d3d1', 'fca5a5', 'fdba74', 'fcd34d', 'fde047', 'bef264', '86efac', '6ee7b7', '5eead4', '67e8f9', '7dd3fc', '93c5fd', 'a5b4fc', 'c4b5fd', 'd8b4fe', 'f0abfc', 'f9a8d4', 'fda4af'], //300 ['94a3b8', '9ca3af', 'a1a1aa', 'a3a3a3', 'a8a29e', 'f87171', 'fb923c', 'fbbf24', 'facc15', 'a3e635', '4ade80', '34d399', '2dd4bf', '22d3ee', '38bdf8', '60a5fa', '818cf8', 'a78bfa', 'c084fc', 'e879f9', 'f472b6', 'fb7185'], //400 ['64748b', '6b7280', '71717a', '737373', '78716c', 'ef4444', 'f97316', 'f59e0b', 'eab308', '84cc16', '22c55e', '10b981', '14b8a6', '06b6d4', '0ea5e9', '3b82f6', '6366f1', '8b5cf6', 'a855f7', 'd946ef', 'ec4899', 'f43f5e'], //500 ['475569', '4b5563', '52525b', '525252', '57534e', 'dc2626', 'ea580c', 'd97706', 'ca8a04', '65a30d', '16a34a','059669', '0d9488', '0891b2', '0284c7', '2563eb', '4f46e5', '7c3aed', '9333ea', 'c026d3', 'db2777', 'e11d48'], //600 ['334155','374151', '3f3f46', '404040', '44403c', 'b91c1c', 'c2410c', 'b45309', 'a16207','4d7c0f', '15803d', '047857', '0f766e', '0e7490', '03609a1', '1d4ed8', '4338ca', '6d28d9', '7e22ce', 'a21caf','be185d', 'be123c'], //700 ['1e293b', '1f2937', '27272a', '262626', '292524', '991b1b', '9a3412','92400e', '854d0e','3f6212', '166534', '065f46', '115e59', '155e75', '075985', '1e40af', '3730a3', '5b21b6', '6b21a8', '86198f', '9d174d', '9f1239'], //800 ['0f172a','111827', '18181b', '171717', '1c1917', '7f1d1d', '7c2d12','78350f', '713f12', '365314', '14532d', '064e3b', '1334e4a', '164e63', '0c4a6e','1e3a8a','312e81', '4c1d95', '581c87','701a75', '831843', '881337'], //900 ['020617', '030712', '09090b', '0a0a0a', '0c0a09', '450a0a', '431407', '451a03', '422006', '1da2e05', '052e16', '022c22', '042f2e', '083344', '082f49', '172554', '1e1b4b', '2e1065', '3b0764', '4a044e', '500724', '4c0519'], //950 ]
--- <div class={tw.grid} style="grid-template-columns:repeat(22, 1fr);"> {colorFamilies.map((family, familyIndex) => ( <div class={tw.palletContainer}> {shades.map((shade, shadeIndex) => ( <PalletItem script={hs} twColor={ "bg-" + family + "-" + shade} hexCode={hexValues[shadeIndex][familyIndex]} /> ))} </div> ))} </div>PalletGridV (vertical)
The data structures of the vertically oriented pallet are exactly the same so won’t be repeated here. However, the JSX loop which builds the grid is flipped so as to gather the shades into separate columns with the color families in different rows.
<div class={tw.grid}> {shades.map((shade, shadeIndex) => ( <div class={tw.palleteWrapper}> {colorFamilies.map((family, familyIndex) => ( <PalletItem script={hs} twColor={"bg-" + family + "-" + shade} hexCode={hexValues[shadeIndex][familyIndex]} /> ))} </div> ))} </div>PalletItem
The essential component rendering a single swatch is the PalletItem comprised of a simple <span> whose background color is set using props.
The PalletItem component accepts three props. The twColor prop is the name of the Tailwind color such as 'red-500'. The hexCode prop is the corresponding hexidecimal value for that color. Finally, the script prop receives a HyperScript from its parents which is used to close the dropdown and then trigger some custom action.
A function in the component script capitalizes the first letter of the color name which is then used to set a title attribute creating a tooltip that will be displayed when the user hovers over the color swatch.
Since the swatch color is created using background colors, the ‘bg-’ prefix is stripped from the Tailwind class before the titlestring is created.
Finally, a Hyperscript attribute on each PalletItem accepts a script prop which should listen for a click and then send the closeDropdown custom event back to the parent <button>. To make this happen, a .colorPalett class is explicitly added to the <button> of each dropdown component by passing this class name into the buttonStyles prop. The custom event should target the .colorPallet class in order to close the dropdown.
To set the background color of the swatch a simple string concatenation expression is used to combine the default styles with the twColor prop. Since there are no default background colors, twMerge() is not needed here.
---interface Props { twColor: string hexCode:string script?:string}
const {twColor, hexCode, script} = Astro.props
import {twMerge} from 'tailwind-merge'
function capitalizeFirstCharacter(str) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1);}
const color = capitalizeFirstCharacter(twColor.replace(/^bg-/, ''))
const tw = { palletItem: 'size-3 rounded-sm overflow-hidden ring-1 ring-slate-600 hover:scale-125',}
---
<span class={tw.palletItem + " " + twColor} title={`${color} (#${hexCode})`} bgcolor={twColor} script={script}></span>Code
Use the Tabs below to explore all the code used to create these examples.
To apply one of these palettes in your Astro project, copy/paste the code from either the Click or Hover activated examples into the Astro file where it will be used and then adjust the file import paths. You will also need the parent dropdown components, either the ClickDropdownMenu_A or HoverDropdownMenu_B.
You will also need to copy/paste the PalletGrid, PalletGridH, PalletGridV, and PalletItem code and put them into separate .astro files.
The import file paths in the sample code are for illustration purposes only and not specific for your project structure. They will all need to be adjusted depending on where in your src folder you place the .astro files.
Unlike the examples here, you probably don’t want to just show an alert when the swatch is clicked but actually perform some more useful action. To give each swatch a custom action, provide a custom Hyperscript for the hs prop of the PalletGrid and this will be passed along eventually reaching the PalettItem component.
However, before your custom action is triggered, you should send closeDropodown to the .colorPallet then settle to smoothly dismiss the dropdown before the user is taken away to something else.
---import PalletGrid from '/components/PalletGrid.astro'import ClickDropdownMenu_A from '/components/ClickDropdownMenu_A.astro'const tw = { icon:'inline-block size-6', button:'colorPallet bg-gray-200 border-2 border-gray-600 dark:bg-gray-700 size-16'}---<ClickDropdownMenu_A id='click-activated-pallet' moveXY='-200,18' buttonStyles={tw.button} duration='180ms'> <img slot="leftIcon" src='/images/tailwind_icon.svg' alt='tailwind icon' class={tw.icon}/> <PalletGrid hs="on click send closeDropdown to the .colorPallet then settle then alert( 'You selected ' + my @title)"/></ClickDropdownMenu_A></div>---import PalletGrid from '/components/PalletGrid.astro'import HoverDropdownMenu_B from '/components/HoverDropdownMenu_B.astro'const tw = { icon:'inline-block size-6', button:'colorPallet bg-gray-200 border-2 border-gray-600 dark:bg-gray-700 size-16'}---<HoverDropdownMenu_B id='hover-activated-pallet' moveXY='-100,18' buttonStyles={tw.button} duration='180ms'> <img slot="leftIcon" src='/images/tailwind_icon.svg' alt='tailwind icon' class={tw.icon}/> <PalletGrid orientation='vertical' hs="on click send closeDropdown to the .colorPallet then settle then alert( 'You selected ' + my @title)"/></HoverDropdownMenu_B>---import PalletGridH from "/components/PalletGridH.astro"import PalletGridV from "/components/PalletGridV.astro"
interface Props { orientation?:string hs?:string}
const {orientation = "horizontal", hs} = Astro.props---
<div > {orientation === 'horizontal' ? <PalletGridH hs={hs}/> : <PalletGridV hs={hs}/>}</div> --- import PalletItem from '/components/PalletItem.astro';
interface Props { hs?: string }
const {hs} = Astro.props
const tw = { grid: 'grid grid-rows-1 gap-2 px-4', palletContainer: 'mt-0 flex flex-col gap-y-2', }
const colorFamilies = ['slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'] const shades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] const hexValues = [ ['f8fafc', 'f9fafb', 'fafafa', 'fafafa', 'fafaf9', 'fef2f2', 'fff7ed', 'fffbeb', 'fefce8', 'f7fee7', 'f0fdf4', 'ecfdf5', 'f0fdfa', 'ecfeff', 'f0f9ff', 'eff6ff', 'eef2ff', 'f5f3ff', 'faf5ff', 'fdf4ff', 'fdf2f8', 'fff1f2'], //50, ['f1f5f9', 'f3f4f6', 'f4f4f5', 'f5f5f5', 'f5f5f4', 'fee2e2', 'ffedd5', 'fefec7', 'fef9c3', 'ecfccb', 'dcfce7', 'd1fae5', 'ccfbf1', 'cffafe, e0f2fe', 'dbeafe', 'e0e7ff', 'ede9fe', 'f3e8ff', 'fae8ff', 'fce7f3', 'ffe4e6'], //100 ['e2e8f0', 'e5e7eb', 'e4e4e7', 'e5e5e5', 'e7e5e4', 'fecaca', 'fed7aa', 'fde68a', 'fef08a', 'd9f99d', 'bbf7d0', 'a7f3d0', '99f6e4', 'a5f3fc', 'bae6fd', 'bfdbfe', 'c7d2fe', 'ddd6fe', 'e9d5ff', 'f5d0fe', 'fbcfe8', 'fecdd3'], //200 ['cbd5e1', 'd1d5db', 'd4d4d8', 'd4d4d4', 'd6d3d1', 'fca5a5', 'fdba74', 'fcd34d', 'fde047', 'bef264', '86efac', '6ee7b7', '5eead4', '67e8f9', '7dd3fc', '93c5fd', 'a5b4fc', 'c4b5fd', 'd8b4fe', 'f0abfc', 'f9a8d4', 'fda4af'], //300 ['94a3b8', '9ca3af', 'a1a1aa', 'a3a3a3', 'a8a29e', 'f87171', 'fb923c', 'fbbf24', 'facc15', 'a3e635', '4ade80', '34d399', '2dd4bf', '22d3ee', '38bdf8', '60a5fa', '818cf8', 'a78bfa', 'c084fc', 'e879f9', 'f472b6', 'fb7185'], //400 ['64748b', '6b7280', '71717a', '737373', '78716c', 'ef4444', 'f97316', 'f59e0b', 'eab308', '84cc16', '22c55e', '10b981', '14b8a6', '06b6d4', '0ea5e9', '3b82f6', '6366f1', '8b5cf6', 'a855f7', 'd946ef', 'ec4899', 'f43f5e'], //500 ['475569', '4b5563', '52525b', '525252', '57534e', 'dc2626', 'ea580c', 'd97706', 'ca8a04', '65a30d', '16a34a','059669', '0d9488', '0891b2', '0284c7', '2563eb', '4f46e5', '7c3aed', '9333ea', 'c026d3', 'db2777', 'e11d48'], //600 ['334155','374151', '3f3f46', '404040', '44403c', 'b91c1c', 'c2410c', 'b45309', 'a16207','4d7c0f', '15803d', '047857', '0f766e', '0e7490', '03609a1', '1d4ed8', '4338ca', '6d28d9', '7e22ce', 'a21caf','be185d', 'be123c'], //700 ['1e293b', '1f2937', '27272a', '262626', '292524', '991b1b', '9a3412','92400e', '854d0e','3f6212', '166534', '065f46', '115e59', '155e75', '075985', '1e40af', '3730a3', '5b21b6', '6b21a8', '86198f', '9d174d', '9f1239'], //800 ['0f172a','111827', '18181b', '171717', '1c1917', '7f1d1d', '7c2d12','78350f', '713f12', '365314', '14532d', '064e3b', '1334e4a', '164e63', '0c4a6e','1e3a8a','312e81', '4c1d95', '581c87','701a75', '831843', '881337'], //900 ['020617', '030712', '09090b', '0a0a0a', '0c0a09', '450a0a', '431407', '451a03', '422006', '1da2e05', '052e16', '022c22', '042f2e', '083344', '082f49', '172554', '1e1b4b', '2e1065', '3b0764', '4a044e', '500724', '4c0519'], //950 ]
--- <div class={tw.grid} style="grid-template-columns:repeat(22, 1fr);"> {colorFamilies.map((family, familyIndex) => ( <div class={tw.palletContainer}> {shades.map((shade, shadeIndex) => ( <PalletItem script={hs} twColor={ "bg-" + family + "-" + shade} hexCode={hexValues[shadeIndex][familyIndex]} /> ))} </div> ))} </div> --- import PalletItem from '/components/PalletItem.astro';
interface Props { hs?: string }
const {hs} = Astro.props
const tw = { grid: 'grid grid-cols-11 gap-2 px-4', palletContainer: 'mt-0 flex flex-col gap-y-2', }
const colorFamilies = ['slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'] const shades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] const hexValues = [ ['f8fafc', 'f9fafb', 'fafafa', 'fafafa', 'fafaf9', 'fef2f2', 'fff7ed', 'fffbeb', 'fefce8', 'f7fee7', 'f0fdf4', 'ecfdf5', 'f0fdfa', 'ecfeff', 'f0f9ff', 'eff6ff', 'eef2ff', 'f5f3ff', 'faf5ff', 'fdf4ff', 'fdf2f8', 'fff1f2'], //50, ['f1f5f9', 'f3f4f6', 'f4f4f5', 'f5f5f5', 'f5f5f4', 'fee2e2', 'ffedd5', 'fefec7', 'fef9c3', 'ecfccb', 'dcfce7', 'd1fae5', 'ccfbf1', 'cffafe, e0f2fe', 'dbeafe', 'e0e7ff', 'ede9fe', 'f3e8ff', 'fae8ff', 'fce7f3', 'ffe4e6'], //100 ['e2e8f0', 'e5e7eb', 'e4e4e7', 'e5e5e5', 'e7e5e4', 'fecaca', 'fed7aa', 'fde68a', 'fef08a', 'd9f99d', 'bbf7d0', 'a7f3d0', '99f6e4', 'a5f3fc', 'bae6fd', 'bfdbfe', 'c7d2fe', 'ddd6fe', 'e9d5ff', 'f5d0fe', 'fbcfe8', 'fecdd3'], //200 ['cbd5e1', 'd1d5db', 'd4d4d8', 'd4d4d4', 'd6d3d1', 'fca5a5', 'fdba74', 'fcd34d', 'fde047', 'bef264', '86efac', '6ee7b7', '5eead4', '67e8f9', '7dd3fc', '93c5fd', 'a5b4fc', 'c4b5fd', 'd8b4fe', 'f0abfc', 'f9a8d4', 'fda4af'], //300 ['94a3b8', '9ca3af', 'a1a1aa', 'a3a3a3', 'a8a29e', 'f87171', 'fb923c', 'fbbf24', 'facc15', 'a3e635', '4ade80', '34d399', '2dd4bf', '22d3ee', '38bdf8', '60a5fa', '818cf8', 'a78bfa', 'c084fc', 'e879f9', 'f472b6', 'fb7185'], //400 ['64748b', '6b7280', '71717a', '737373', '78716c', 'ef4444', 'f97316', 'f59e0b', 'eab308', '84cc16', '22c55e', '10b981', '14b8a6', '06b6d4', '0ea5e9', '3b82f6', '6366f1', '8b5cf6', 'a855f7', 'd946ef', 'ec4899', 'f43f5e'], //500 ['475569', '4b5563', '52525b', '525252', '57534e', 'dc2626', 'ea580c', 'd97706', 'ca8a04', '65a30d', '16a34a','059669', '0d9488', '0891b2', '0284c7', '2563eb', '4f46e5', '7c3aed', '9333ea', 'c026d3', 'db2777', 'e11d48'], //600 ['334155','374151', '3f3f46', '404040', '44403c', 'b91c1c', 'c2410c', 'b45309', 'a16207','4d7c0f', '15803d', '047857', '0f766e', '0e7490', '03609a1', '1d4ed8', '4338ca', '6d28d9', '7e22ce', 'a21caf','be185d', 'be123c'], //700 ['1e293b', '1f2937', '27272a', '262626', '292524', '991b1b', '9a3412','92400e', '854d0e','3f6212', '166534', '065f46', '115e59', '155e75', '075985', '1e40af', '3730a3', '5b21b6', '6b21a8', '86198f', '9d174d', '9f1239'], //800 ['0f172a','111827', '18181b', '171717', '1c1917', '7f1d1d', '7c2d12','78350f', '713f12', '365314', '14532d', '064e3b', '1334e4a', '164e63', '0c4a6e','1e3a8a','312e81', '4c1d95', '581c87','701a75', '831843', '881337'], //900 ['020617', '030712', '09090b', '0a0a0a', '0c0a09', '450a0a', '431407', '451a03', '422006', '1da2e05', '052e16', '022c22', '042f2e', '083344', '082f49', '172554', '1e1b4b', '2e1065', '3b0764', '4a044e', '500724', '4c0519'], //950 ]
--- <div class={tw.grid}> {shades.map((shade, shadeIndex) => ( <div class={tw.palletContainer}> {colorFamilies.map((family, familyIndex) => ( <PalletItem script={hs} twColor={"bg-" + family + "-" + shade} hexCode={hexValues[shadeIndex][familyIndex]} /> ))} </div> ))} </div>---interface Props { twColor: string hexCode:string script?:string}
const {twColor, hexCode, script } = Astro.props
import {twMerge} from 'tailwind-merge'
function capitalizeFirstCharacter(str) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1);}
const color = capitalizeFirstCharacter(twColor.replace(/^bg-/, ''))
const tw = { palletItem: 'size-3 rounded-sm overflow-hidden ring-1 ring-slate-600 hover:scale-125',}---
<span class={tw.palletItem + " " + twColor} title={`${color} (#${hexCode})`} bgcolor={twColor} script={script}></span>Usage
Although this hyperComponent is more complicated than other examples, it provides a means to build widget construction interfaces whereby the color values can be picked from a pallet and applied to the styling of an element. Conveniently, the Tailwind library color families are now pickable from swatches.