SecretoCho
menu

component 16 / 28WORKING

SC Color Card System

type
Code Component
platform
Framer
license
SecretoCho Design
needs JavaScript

demo · runs with JavaScript

fig 00 · live demo, ported from SC_ColorCardSystem.tsx and SC_ColorCardSystem_simple.tsx

JSON-driven colour specification cards: swatch, value rows, RAL and Pantone matches, copy-to-clipboard CSS; plus a tokens variant filtered by theme.

SCColorCard renders a grid of colour specification cards from a JSON array. Each card shows the swatch with its code and name in auto-contrast text, then the value rows (HEX, RGB, CMYK coated and uncoated, Lab D50 and D65), the RAL and Pantone cross-matches with a good/weak badge, and a footer with Copy CSS and View Color buttons. Typography is split into code, name, label and value fonts, with Recursive variable-font axes per group.

The second file, SC_ColorCardSystem_simple.tsx (SCDesignSystemColors), is the design-system variant: the same card chrome for CSS tokens with HEX, RGBA, HSLA and HSBA rows, a light/dark theme filter, alpha-aware contrast and a single Copy CSS button. The demo offers both.

  • Design System
  • Data
  • UI
  • Typography

Main

Overview

Built With
React (hooks), CSS (inline), ResizeObserver, Clipboard API, Framer Code Component API
Layout Support
CSS grid, 1–6 columns; collapses to one column under the breakpoint when Responsive is on
Orientation
Vertical cards: swatch on top, rows below, footer buttons
Ideal Use Case
Brand colour sheets, design-system token pages, print-spec handoffs

Tags

  • color
  • colour card
  • design system
  • ncs
  • ral
  • pantone
  • cmyk
  • lab
  • css token
  • clipboard
  • json

Code comment

SC_ColorCardSystem.tsx has no doc comment.

Dependencies

Technologies
None beyond React and the Framer runtime
Notes
Uses ResizeObserver for the responsive check and navigator.clipboard for Copy CSS; the simple variant also reads prefers-color-scheme via matchMedia.

Complexity

Logic Level
Medium (JSON parse and validation, derived contrast colour, conditional match rows, hover state per card/row/button)
Runtime Cost
Low (no animation loop; one ResizeObserver; inline styles rebuilt per render)
Component Size
~84 KB TSX (84,124 bytes, 1,803 lines); simple variant ~56 KB (55,908 bytes, 1,432 lines)
Notes
Most of the size is the property-control tree: 19 top-level controls, several of them object groups with variable-font axes.

Guide

Instructions

  1. Drop SCColorCard (or SCDesignSystemColors for tokens) into a frame.
  2. Paste a JSON array into Color Data. Required keys: hex, colorCode, colorName (the simple variant needs hex, colorCode and theme). Keys must be quoted.
  3. Optional keys per colour: rgb, cmykCoated, cmykUncoated, labD50, labD65, ral {code, match}, pantone {code, match}, colorLink, cssToken, colorSystem (ncs / pantone / ral / custom; a match of the same system is hidden).
  4. Set Layout (columns, gap, card max width, radius, border, responsive breakpoint) and Visibility (body, footer, matches).
  5. Style the four text roles with their Font controls; turn on Use Variable Font to expose the MONO / CASL / CRSV / slnt / wght axes per group.
  6. Pick a Shadow Style: standard, neumorphism or custom.
  7. Keep Show Parse Errors on while editing: a bad JSON shows the reason and falls back to the built-in two colours.

Examples / Presets

  • Default

    SCColorCard defaults: the two built-in NCS colours, 3 columns, body, footer and matches shown.

  • Swatches only

    visibility.showBody
    false
    visibility.showFooter
    false
    visibility.showMatches
    false
    colorDisplay.colorHeight
    200
  • Simple

    SCDesignSystemColors defaults: selectedTheme=light, 4 columns, HEX / RGBA / HSLA / HSBA rows, Copy CSS footer.

  • Simple dark tokens

    selectedTheme
    dark
    layout.columns
    2 (the data’s dark-theme tokens only)
  • Site style

    useVariableFont
    true
    layout.columns
    4
    layout.gap
    10
    layout.borderRadius
    0
    spacing.contentPadding
    10px
    spacing.itemSpacing
    5
    colorDisplay.wght
    800 (the old site’s Color-Card-two section: Recursive, colour codes in MONO 1, B-W token borders and labels)

variant (card | simple) is the demo’s switch between the two files, not a control of either component.

Mechanics

How it Works

  • Data: parseColorData accepts an array or a JSON string, validates the required keys per item and returns the built-in defaults with an error message when anything fails (missing keys are named; the hints for unquoted keys, single quotes and trailing commas appear only on an “Unexpected token” message, which current browsers no longer give for the first two, so the raw message shows).
  • Contrast: calculateLuminance weighs R, G and B (0.299 / 0.587 / 0.114); above 0.5 the swatch text is black, else white, unless Text Color Override is set. The simple variant also alpha-blends 8-digit HEX against a white or dark system background read from prefers-color-scheme.
  • Rows: HEX always; RGB, CMYK coated/uncoated and Lab D50/D65 only when present. RAL and Pantone match cards appear when the colour has them and its colorSystem is a different system; the match word (good / perfect vs anything else) picks the badge colours.
  • Fonts: toVariableStack rewrites the first family to “<Family> Variable”; buildVariationString clamps MONO/CASL/CRSV to 0–1, slnt to −15–0 and wght to 300–1000, and unsets font-weight when the wght axis is active.
  • Footer: Copy CSS writes “--token: #hex;” to the clipboard and shows a toast for the configured duration; View Color opens colorLink in a new tab.
  • Responsive: a ResizeObserver on the container switches the grid to one column at or under the breakpoint.

Performance & Tuning

  • Cards are plain DOM: cost scales with the number of colours × rows; there is no animation loop.
  • Every card, row and button has its own hover state in the parent; very long sheets re-render the whole grid on hover. Split large palettes into several instances.
  • Shadows on hover multiply offset and blur (×4 and ×3 for the standard style); neumorphism draws two shadows per card.

Compatibility & Limits

  • Evergreen browsers; needs ResizeObserver and navigator.clipboard (clipboard requires a secure context).
  • The simple variant needs 8-digit HEX (#RRGGBBAA) for translucent tokens; 3-digit HEX is not handled by its parser.
  • JSON only: object literals with unquoted keys are rejected; the hint “Keys must be quoted” shows only on an “Unexpected token” message and with a literal id: or colorCode: in the input.

Quality

Accessibility

  • Swatch text picks black or white from the colour’s luminance; set Text Color Override when a brand needs a fixed colour.
  • Copy CSS and View Color are real <button>s; the toast is visual only (no aria-live region).
  • Row labels are uppercase 9–11 px text: check contrast against your card background.

Security & Privacy

  • No fetch, no storage, no tracking in either file.
  • Clipboard: navigator.clipboard.writeText on the Copy CSS click (user gesture only).
  • External links: View Color calls window.open(colorLink, "_blank") with whatever URL the JSON holds, without noopener, so the opened page gets window.opener; the built-in sample data links to app.ncscolour.com. Only the browser follows it, on click.
  • Input: Color Data goes through JSON.parse only; nothing is evaluated. Rendered as text, no dangerouslySetInnerHTML.
  • The simple variant reads prefers-color-scheme through matchMedia and listens for changes; both use a ResizeObserver. No permissions.

Reference

Props

nametypedefaultdescription
colorDataJSONstringthe two built-in NCS colours as JSONColor Data. Paste a valid JSON array; keys must be quoted. Add colorSystem (ncs / pantone / ral / custom) to control match visibility.
showParseErrorbooleantrueShow Parse Errors. Display an error message if JSON parsing fails.
visibilityobjectshowBody=true, showFooter=true, showMatches=trueVisibility: body content, footer buttons, colour matches.
fontFontStyleFramer font controlFont. Fallback for the font family only; size and weight come from each role’s built-in fallback.
useVariableFontbooleanfalseUse Variable Font. Exposes the MONO / CASL / CRSV / slnt / wght axes in the Color Display, Label and Value groups.
layoutobjectcolumns=3, gap=20, cardMaxWidth=360, borderRadius=8, borderColor=rgba(0,0,0,0.06), responsive=true, breakpoint=600Layout. Columns 1–6; gap and card max width in px; breakpoint 300–1200 px, shown when Responsive is on.
shadowsobjectshadowStyle=standard, enableShadow=true, shadowColor=rgba(0,0,0,0.04), shadowHoverColor=rgba(0,0,0,0.1), shadowOffsetX=0, shadowOffsetY=2, shadowBlur=10, neuLightShadow=#ffffff, neuDarkShadow=#d1d1d1, neuDistance=20, neuBlur=60, neuInset=false, customShadow=0 2px 10px rgba(0,0,0,0.04), customHoverShadow=0 8px 30px rgba(0,0,0,0.1), shadowTransition=0.3s easeShadows. Standard, neumorphism or custom; each style shows its own sub-controls.
spacingobjectcontentPadding=20px, itemSpacing=16, rowSpacing=8px, cardPadding=10px 12pxSpacing. Content padding, item spacing (5–40 px), row padding, match-card padding.
colorCodeFontFontStyleFramer font controlColor Code Font. The large code on the swatch.
colorNameFontFontStyleFramer font controlColor Name Font. The name under the code.
colorDisplayobjectcolorHeight=160, textColor="" (auto), MONO=0, CASL=0, CRSV=0, slnt=0, wght=600Color Display. Swatch height 100–300 px; Text Color Override (auto-contrast if empty); variable axes for the swatch text.
labelFontFontStyleFramer font controlLabel Font. The uppercase row labels.
labelsobjectlabelColor=#999999, MONO=0, CASL=0, CRSV=0, slnt=0, wght=600Label Controls. Colour and variable axes for labels.
valueFontFontStyleFramer font controlValue Font. Row values, badges and buttons.
valuesobjecttextColor=#333333, MONO=1, CASL=0, CRSV=0, slnt=0, wght=400Value Controls. Colour and variable axes for values.
footerobjectbuttonPadding=15px, borderColor=#999999, borderHoverColor=#666666Footer Controls. Button padding and dashed border colours (the hover colour is also the card’s hover border).
colorsobjectcardBg=#ffffff, cardHoverBg=#fafafa, accentBg=#F5F3F0, rowBg=transparent, rowHoverBg=#F5F3F0Colors. Card, match-card accent and row backgrounds.
matchQualityobjectgoodBg=#d4edda, goodText=#155724, weakBg=#fff3cd, weakText=#856404Match Quality. Badge colours for good/perfect vs weak matches; also used by the copy toast.
notificationsobjectduration=3000, successBg=#d4edda, successText=#155724, successBorder=#c3e6cb, errorBg=#f8d7da, errorText=#721c24, errorBorder=#f5c6cbNotifications. Toast duration 1000–10000 ms and colours (see the note under this table).

In SC_ColorCardSystem.tsx only notifications.duration is read; the six notification colour controls are declared but the toast takes its colours from matchQuality. In SC_ColorCardSystem_simple.tsx the colors.codeBg and colors.dividerColor controls are declared but never read. Render-time fallbacks differ from some control defaults (for example layout.gap falls back to 30, colorDisplay.colorHeight to 200, spacing.contentPadding to 25px when the group is missing).

Notes & Tips

  • Set colorSystem on each colour: an NCS colour then shows its RAL and Pantone matches, a Pantone colour hides the Pantone row.
  • Use cssToken to get the Copy CSS button; without colorLink and cssToken the footer is not rendered.
  • For token sheets with alpha (shadows, borders) use the simple variant and 8-digit HEX; the contrast text then follows the system theme.
  • Only radius 0 keeps sub-elements square: under 8 px they get radius / 2, and from 8 px they cap at 4.

Troubleshooting / FAQ

The cards show the two default colours, not mine

The JSON failed validation; turn on Show Parse Errors to read why (a missing hex / colorCode / colorName is named; for unquoted keys, single quotes or a trailing comma current browsers show their own JSON message).

No RAL or Pantone row

The colour has no ral / pantone object, Show Color Matches is off, or its colorSystem equals that match system (same-system matches are hidden).

Copy CSS does nothing

The clipboard API needs HTTPS (a secure context) and a real click; the toast only confirms the call was made.

Swatch text is hard to read on mid-tone colours

The threshold is luminance 0.5; set colorDisplay.textColor to force a colour.

Simple variant shows no cards

selectedTheme filters by each item’s theme field; items without theme=light|dark are filtered out.

Source

Header comment

SC_ColorCardSystem.tsx has no doc comment.

props [REF]

Key excerpt

The swatch picks black or white text from the colour’s own luminance (weighted RGB over 255, threshold 0.5), so each card’s code stays readable on its colour without a manual setting.

SC_ColorCardSystem.tsx · lines 134–147 · tsx
// Calculate luminance using W3C formulafunction calculateLuminance(hex: string): number {    const rgb = hex.replace("#", "")    const r = parseInt(rgb.substr(0, 2), 16)    const g = parseInt(rgb.substr(2, 2), 16)    const b = parseInt(rgb.substr(4, 2), 16)    return (0.299 * r + 0.587 * g + 0.114 * b) / 255}// Get contrast text color based on backgroundfunction getContrastTextColor(bgHex: string): string {    const luminance = calculateLuminance(bgHex)    return luminance > 0.5 ? "#000000" : "#FFFFFF"}

Credits

Credits

© SecretoCho Design

license
SecretoCho Design

SecretoCho Design

Disclaimer

Proves

Hiring a design engineer?

I’m open to senior design engineer roles: remote from Belgrade, or relocation with visa sponsorship. Write to me, or read the CV first. Client work stays selective, one project at a time.

sc@secretocho.design

read the CV · LinkedIn