---
title: SC Simple Data Display (Pattern)
description: A CMS-friendly label:value list with a leading pattern column.
url: https://secretocho.design/lab/sc-simple-data-display-pattern/
type: SoftwareSourceCode
status: working
published: 2025-08-26
updated: 2025-08-26
---

# SC Simple Data Display (Pattern)

> A CMS-friendly label:value list with a leading pattern column.

component 15 / 28 · WORKING

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

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

*fig 00 · live demo, ported from **SC\_DataDisplay\_w\_Pattern.tsx***

CMS-friendly label:value list with a leading pattern column, responsive desktop/stacked layouts, and per-column variable-font axis tuning.

CMS-friendly label/value list with an optional pattern column for visual rhythm. Supports variable-font axes per column, responsive switch to a stacked layout, and a friendly placeholder when no data is provided.

- Data
- Typography
- Layout

## Main

### Overview

- **Built With**: React, CSS, Framer Code Component API
- **Layout Support**: Fully Responsive (switches to stacked view under breakpoint)
- **Orientation**: Pattern column → label → value (desktop); stacked rows (mobile)
- **Ideal Use Case**: Pricing/spec blocks, feature matrices, project metadata, compact CMS hand-offs

### Tags

- data-display
- pattern
- variable-font
- responsive
- cms
- typography

### Code comment

```tsx
/**
 * Simple Data Display (Pattern)
 * © SecretoCho Design 2025 (https://secretocho.design)
 * CMS-friendly label/value list with optional pattern column.
 * Variable-font axis control per column; responsive layout via ResizeObserver.
 * @framerDisableUnlink
 * @framerSupportedLayoutWidth any
 * @framerSupportedLayoutHeight any
 */
```

### Dependencies

- **Technologies**: None (pure React + CSS)
- **Notes**: No runtime libraries required; works with Framer’s runtime. Variable font axes require a VF family in your project.

### Complexity

- **Logic Level**: Low–Medium (string parsing + responsive observer)
- **Runtime Cost**: Very Low (text rendering)
- **Component Size**: ~3–4 KB (raw TSX)
- **Notes**: Axes apply via font-variation-settings; provide a VF stack or disable Variable Font.

## Guide

### Instructions

1. **Content:** In **Content**, enter one row per line as Label::Value (or change **Delimiter**).
2. **Pattern:** Choose **Pattern**, **Pattern Color**, **Pattern Width**, and **Pattern Align**.
3. **Typography:** Pick **Font**, **Label Color**, **Value Color**.
4. **Variable Fonts:** Toggle **Variable Font**; tune **Label Axes** and **Value Axes** (MONO, CASL, CRSV, slnt, wght).
5. **Layout:** Set **Label Width**, **Column Gap**, **Row Gap**, enable **Responsive** and set **Breakpoint**.
6. **Empty State:** If no content, a helper placeholder appears automatically.

### Examples / Presets

- Preset: Spec Sheet Minimal
  
  ```txt
  CPU::Apple M3
  RAM::16 GB
  Storage::512 GB SSD
  Display::14" 3024×1964
  ```
  
- Preset: Project Meta
  
  ```txt
  Client::SecretoCho Design
  Scope::UI Engineering
  Stack::Framer, TypeScript, Three.js
  Status::In Production
  ```
  

- Pattern //, Pattern Align right, CASL slight 0.2 on labels.

## Mechanics

### How it Works

- **Parsing:** Splits content by newline → each line split by delimiter → {label, value}.
- **Pattern Column:** Renders pattern as text with reduced opacity; width fixed by **Pattern Width**.
- **Variable Fonts:** If **Variable Font** is on, converts the first family in the stack to its " Variable" form and applies font-variation-settings per column; falls back to cssFontWeight when wght isn’t applied.
- **Responsive:** A ResizeObserver checks container width and flips to a stacked layout at **Breakpoint**.

### Performance & Tuning

- Prefer concise patterns (e.g. #, //, ·) to avoid visual noise.
- Long values: rely on built-in word-break: break-word.
- Large lists: rendering is light; main cost is text layout—keep **Row Gap** modest.

### Compatibility & Limits

- Modern evergreen browsers.
- Variable font axes require VF support; if unavailable, component falls back to font-weight.
- No server/client fetches; purely presentational.

## Quality

### Accessibility

- Treat the list as **terms + descriptions**. For maximum semantics, consider placing the component inside a region with an accessible name, or replicate with \<dl\>/\<dt\>/\<dd\> when exporting to code.
- Pattern column is decorative; if it confuses SRs, wrap it with aria-hidden="true".
- Placeholder uses aria-live="polite" to hint updates when content becomes available.

### Security & Privacy

- No network calls; no storage; no device permissions.
- Inputs are rendered as text (not HTML) — no dangerouslySetInnerHTML, no eval.
- Main foot-gun is **very large content** leading to long pages; paginate or limit rows in CMS.

## Reference

### Props

| name | type | default | description |
| --- | --- | --- | --- |
| content | string | "Label::Value\n..." | Multi-line source (one row per line). |
| delimiter | string | "::" | Separator between label and value. |
| pattern | string | "#" | Characters painted in the pattern column. |
| patternColor | color | rgba(0,0,0,0.64) | Pattern text color. |
| patternWidth | number(px) | 30 | Fixed width of the pattern column. |
| patternAlign | enum | center | Pattern text alignment (left\|center\|right). |
| font | FontValue | Recursive, ... | Shared base font for both columns. |
| labelColor | color | #666 | Label text color. |
| valueColor | color | #111 | Value text color. |
| variableAxes | boolean | true | Enable variable-font axes. |
| labelAxes | Axes | { MONO:1, CASL:0, CRSV:0, slnt:0, wght:400, cssFontWeight:400 } | – |
| valueAxes | Axes | { MONO:1, CASL:0, CRSV:0, slnt:0, wght:600, cssFontWeight:600 } | – |
| labelWidth | number(px) | 180 | Fixed label column width (desktop). |
| gap | number(px) | 20 | Gap between columns. |
| rowGap | number(px) | 8 | Gap between rows (desktop). |
| mobileRowGap | number(px) | 24 | Gap between groups on mobile. |
| responsive | boolean | true | Enable layout switch based on width. |
| breakpoint | number(px) | 600 | Width to switch to stacked layout. |
| placeholderMinHeight | number(px) | 120 | Minimum height of the empty-state box. |

### Notes & Tips

- Use **monospace** flavor (MONO: 1) for technical feel in values.
- Keep **Label Width** tight to encourage values to wrap, not labels.
- Patterns read best at 24–36px width; align left for subtlety, center/right for ornament.

### Troubleshooting / FAQ

My rows don’t split.

Ensure your delimiter matches **Delimiter** (default ::).

Text wraps oddly.

Increase **Label Width** or adjust **gap**.

Variable axes not applying.

Confirm your chosen font is a Variable Font; otherwise disable **Variable Font** or rely on cssFontWeight.

## Source

### Header comment

*SC\_DataDisplay\_w\_Pattern.tsx · lines 6–11 · header comment*

```tsx
/**
 * Simple Data Display (Pattern)
 * © SecretoCho Design 2025 (https://secretocho.design)
 * CMS-friendly label/value list with optional pattern column.
 * Variable-font axis control per column; responsive layout via ResizeObserver.
 */
```

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

### Key excerpt

Rows split on the delimiter (a value may contain it), and a ResizeObserver switches to the stacked layout at the breakpoint.

*SC\_DataDisplay\_w\_Pattern.tsx · lines 137–175 · tsx*

```tsx
    const dataRows = useMemo(() => {
        if (!content || content.trim() === "") return []

        return content
            .split("\n")
            .filter((line) => line.trim())
            .map((line) => {
                const parts = line.split(delimiter)
                const label = parts[0]?.trim() || ""
                const value = parts.slice(1).join(delimiter).trim() || ""
                return { label, value }
            })
    }, [content, delimiter])

    const hasValidData = dataRows.length > 0

    // Determine display mode
    const [isMobile, setIsMobile] = React.useState(false)

    React.useEffect(() => {
        if (!responsive) {
            setIsMobile(false)
            return
        }

        const checkWidth = () => {
            if (containerRef.current) {
                setIsMobile(containerRef.current.offsetWidth <= breakpoint)
            }
        }

        checkWidth()
        const resizeObserver = new ResizeObserver(checkWidth)
        if (containerRef.current) {
            resizeObserver.observe(containerRef.current)
        }

        return () => resizeObserver.disconnect()
    }, [responsive, breakpoint])
```

## Credits

### Credits

Variable-font axis controls inspired by modern VF practices (e.g., Recursive).  
Development, Implementation and Framer adaptation by **SecretoCho Design**.

- **license**: SecretoCho Design

SecretoCho Design 2025

### Disclaimer

Provided “as is” for visual/UX purposes. You are responsible for verifying performance, accessibility, and any font licensing in your project.

## 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/)
