---
title: SC Tag Display
description: Turns a comma-separated string into tag pills with variable-font hover states.
url: https://secretocho.design/lab/sc-tag-display/
type: SoftwareSourceCode
status: working
published: 2025-08-28
updated: 2025-08-28
---

# SC Tag Display

> Turns a comma-separated string into tag pills with variable-font hover states.

component 09 / 28 · WORKING

- **type**: Code Component
- **platform**: Framer
- **last update**: 2025-08-28
- **read time**: 6–8 min
- **license**: SecretoCho Design

![A still of the SC Tag Display demo, as its module draws it with reduced motion.](https://secretocho.design/_astro/still.CStjb_za_24sr4n.webp)

*fig 00 · live demo, ported from **SC\_TagDisplay.tsx***

Transforms a comma-separated string into responsive “tag pills” with hover states, borders, spacing, and variable-font axis animation (MONO/CASL/CRSV/slnt/wght) for smooth weight/style transitions; no external libs.

A lightweight tag/chip renderer for Framer. Feed it a comma-separated list and it outputs accessible, responsive pills with configurable padding, gap, border, and colors. If your primary typeface ships a “Variable” face (e.g., Recursive Variable), you can animate axes on hover for a subtle, high-end typographic feel.

- UI
- Typography
- Metadata

## Main

### Overview

- **Built With**: React, CSS, Framer Code Component API
- **Layout Support**: Fully Responsive (auto-wrap)
- **Orientation**: Inline Tag List
- **Ideal Use Case**: Metadata chips, taxonomy tags, blog/category badges, filters

### Tags

- tags
- chips
- badges
- variable fonts
- hover
- typography
- UI
- pills

### Code comment

```tsx
/**
 * SC Tag Display v1
 * © SecretoCho Design 2025 (https://secretocho.design)
 * Renders comma-separated tags as styled pills with optional variable-font axes.
 * Hover states can morph axes (e.g., wght) without extra libraries.
 * @framerDisableUnlink
 */
```

### Dependencies

- **Technologies**: None (no external libraries)
- **Notes**: Variable-font animation requires a variable face in your first family (e.g., “Recursive Variable”).

### Complexity

- **Logic Level**: Low (string split + style)
- **Runtime Cost**: Very Low (static DOM, simple hover transitions)
- **Component Size**: ~2–3 KB (raw TSX)
- **Notes**: Very large tag counts create many DOM nodes—paginate or truncate if needed.

## Guide

### Instructions

1. Set **Data** to a comma-separated list, e.g. UI, Motion, Generative.
2. Choose **Tag BG**, **Text**, **Hover BG**; adjust **Padding**, **Gap**, and **Border**.
3. Enable **Variable Font** and tune **Axes** (MONO/CASL/CRSV/slnt/wght).
4. Toggle **Hover Axes** to morph typography on hover (e.g., wght: 600 → 700).
5. Bind to CMS by mapping a text field into **Data**.

### Examples / Presets

- Minimal
  
  gap=6, padding=4px 8px, border width=0.
  
- Bold hover
  
  base wght=500 → hover wght=700; subtle bg shift.
  
- Neutral UI chips
  
  BG #F3F3F3, text #111, border #DDD, radius=8.
  

## Mechanics

### How it Works

- Parses data by commas → trims → filters empties → maps into \<div\> pills.
- Computes a font stack; if **Variable Font** is on, first family is coerced to its " Variable" face (e.g., Recursive → Recursive Variable).
- Builds CSS font-variation-settings strings from **Axes**; if "wght" is present, CSS font-weight is omitted to avoid conflicts.
- On hover, swaps background and (optionally) variation settings for smooth axis interpolation.

### Performance & Tuning

- Static layout—no RAF, no listeners.
- Prefer shorter tag lists for mobile; keep **Gap** small to reduce line wraps.
- When animating wght, keep deltas modest (e.g., 500→650) for cleaner interpolation.

### Compatibility & Limits

- Works in modern evergreen browsers.
- Variable-font axes require a variable face installed/loaded; otherwise fallback to classic font-weight.
- Right-to-left languages: tags render left-to-right by default; wrap in an RTL container if needed.

## Quality

### Accessibility

- Tags are static text by default; if interactive, wrap each in a button/link and provide aria-labels.
- Ensure color contrast for text vs. background (WCAG AA).

### Security & Privacy

- No dangerouslySetInnerHTML; tags are plain strings.
- No network calls; no data stored.
- Be mindful not to inject untrusted CSS tokens into data.

## Reference

### Props

| name | type | default | description |
| --- | --- | --- | --- |
| data | string | “tag 1, tag 2, tag 3” | Comma-separated tags |
| tagBackgroundColor | string(Color) | #F3F3F3 | Default chip background |
| tagTextColor | string(Color) | #000 | Chip text color |
| tagHoverBackgroundColor | string(Color) | #E0E0E0 | BG on hover |
| font | object(FontValue) | — | Family/size/weight/spacing/style |
| border.color | string(Color) | #CCC | Border color |
| border.width | number | 1 | Border width (px) |
| border.radius | number | 6 | Corner radius (px) |
| padding | string | “6px 10px” | Chip padding |
| gap | number | 8 | Gap between chips (px) |
| variableAxes | boolean | true | Enable variable-font axes |
| axes | object(Axes) | see defaults | Base axes (MONO/CASL/CRSV/slnt/wght/cssFontWeight) |
| variableAxesHover | boolean | true | Enable hover axes morph |
| hoverAxes | object(Axes) | see defaults | Hover axes |

### Notes & Tips

- If your first font family lacks a variable face, disable **Variable Font** to avoid mismatches.
- Keep cssFontWeight in **Axes** as a fallback when the wght axis isn’t applied.
- For clickable tags, move hover logic into CSS classes and add focus styles.

### Troubleshooting / FAQ

Hover doesn’t change weight.

Your font may not expose a wght axis; use cssFontWeight fallback or choose a variable face.

Text looks jumpy on hover.

Reduce axis deltas; try easing via longer transition durations.

Fonts don’t switch to “Variable”.

Ensure the variable font is loaded and named with the “ Variable” suffix in your stack.

## Source

### Header comment

*SC\_TagDisplay.tsx · lines 72–76 · the first doc comment (the header, lines 1–3, holds only Framer’s annotations)*

```tsx
/**
 * Converts first family in the stack to its "Variable" face if not already.
 * This mirrors your previous component behavior (great for Recursive etc.).
 * If your font doesn’t ship a " Variable" face, keep variableAxes=false.
 */
```

[props \[REF\]](#reference)

### Key excerpt

Each axis is clamped to its range and joined into one font-variation-settings string; hover swaps in a second string.

*SC\_TagDisplay.tsx · lines 100–117 · tsx*

```tsx
function clamp(n: number, min: number, max: number): number {
    return Math.min(max, Math.max(min, n))
}

function buildVariationString(a?: Axes): string {
    if (!a) return ""
    const MONO = clamp(a.MONO ?? 1, 0, 1)
    const CASL = clamp(a.CASL ?? 0, 0, 1)
    const CRSV = clamp(a.CRSV ?? 0.5, 0, 1)
    const slnt = clamp(a.slnt ?? 0, -15, 0)
    const wght = clamp(a.wght ?? 600, 300, 1000)
    // Order is not critical, but we keep it consistent
    return `"MONO" ${MONO}, "CASL" ${CASL}, "CRSV" ${CRSV}, "slnt" ${slnt}, "wght" ${wght}`
}

function hasWghtAxis(variation: string): boolean {
    return /"wght"\s*-?\d+/.test(variation)
}
```

## Credits

### Credits

Component design & implementation by **SecretoCho Design**.

- **license**: SecretoCho Design

SecretoCho Design 2025

### Disclaimer

Provided “as is.” Validate accessibility, licensing for fonts, and performance in your project before shipping.

## Proves

- [Creative coding](https://secretocho.design/about/#capabilities)

## 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](mailto:sc@secretocho.design)

[read the CV](https://secretocho.design/cv/) · [LinkedIn](https://www.linkedin.com/in/secretocho/)
