SecretoCho
menu

component 18 / 28WORKING

SC Props Generator

type
Code Component
platform
Framer
license
SecretoCho Design
needs JavaScript

demo · runs with JavaScript

fig 00 · live demo, ported from SC_PropsTable.tsx

Text-to-table props documentation: delimiter-separated lines become a desktop table or a collapsible mobile list, with variable-font axes per column.

Props Generator renders a component’s property table from plain text. One line per prop, four columns separated by a delimiter (name :: type :: default :: description), and the component draws either a four-column desktop table or a collapsible mobile list with name and type chips. Variable-font axes for labels and values are separate, so a mono value column can sit next to a casual label.

It is the component behind the props rows of the old site’s component pages: the CMS Props field uses the same name::type::default::description lines.

  • Utilities
  • Data
  • Design System
  • Typography

Main

Overview

Built With
React (hooks), CSS (inline), Framer Code Component API
Layout Support
Fills the frame width; the desktop / mobile variant is a prop, not a media query
Orientation
Rows: 25 / 15 / 20 % + flexible description column (desktop); name + type chips with an expandable default / desc panel (mobile)
Ideal Use Case
Component documentation pages, API tables inside Framer, design-system reference

Tags

  • props
  • table
  • documentation
  • api
  • delimiter
  • variable font
  • recursive
  • design system

Code comment

SC_PropsTable.tsx has no doc comment.

Dependencies

Technologies
None (pure React + inline CSS)
Notes
No external libraries; the variable-font axes assume a Recursive-style family (MONO, CASL, CRSV, slnt, wght).

Complexity

Logic Level
Low–Medium (line and delimiter parsing, two row renderers, axis strings)
Runtime Cost
Very Low (plain DOM, hover state per row)
Component Size
~24 KB TSX (23,726 bytes, 734 lines)
Notes
DesktopRow and MobileRow are declared inside the component, so React remounts them on every parent render (their hover / expanded state resets).

Guide

Instructions

  1. Drop Props Generator into a frame.
  2. Fill Props Data: one prop per line, columns separated by the Delimiter (default ::): name::type::default::description.
  3. Pick the Variant: Desktop (XL -- Main), Mobile Collapsed (S -- Main) or Mobile Expanded (S -- Extended). Use Framer breakpoints to switch variants.
  4. Set the Font; turn on Variable Font to expose Label Axes and Value Axes.
  5. Adjust the border, background, card and hover colours.

Examples / Presets

  • Desktop

    variant
    XL -- Main (the default four-column table)
  • Mobile Collapsed

    variant
    S -- Main (name and type chips; tap a row for default and desc)
  • Mobile Expanded

    variant
    S -- Extended (every row starts open)
  • Site style

    variableAxes
    true
    labelAxes.MONO
    1
    labelAxes.wght
    500
    valueAxes.MONO
    1
    valueAxes.wght
    400 (the old site’s component-page settings; its font and colours come from the demo module)

The default Props Data (four pattern props) is the text the component ships with; the demo’s “Site style” rows are the CMS Props of an existing lab entry.

Mechanics

How it Works

  • Parse: Props Data is split on newlines, blank lines dropped, each line split on the delimiter and trimmed; a missing column falls back to the placeholder word (name, type, default, description).
  • Desktop row: four cells at 25 / 15 / 20 % and flex 1, separated by 1 px lines; name and default sit in bordered chips, type and description are plain text; hover swaps the row background and text colour.
  • Mobile row: a top row with name: and type: chips and a chevron; default: and desc: live in a panel that toggles on click. S -- Extended sets every row open on mount.
  • Fonts: toVariableStack rewrites the first family to “<Family> Variable”; two axis strings are built (labels and values) and font-weight is unset when a wght axis is present.
  • Empty state: with no rows the component shows the expected format and an example line.

Performance & Tuning

  • Plain DOM; cost is one row per line. Dozens of props are fine.
  • Hover and expanded state live inside row components declared in the render function, so each parent render recreates them; keep the parent’s props stable.

Compatibility & Limits

  • Evergreen browsers; no APIs beyond React.
  • The variant does not respond to width by itself: switch it per Framer breakpoint.
  • Delimiter characters that appear inside a description will split the line; choose a delimiter the text never uses. An empty Delimiter splits each line into characters.
  • With Variable Font on, the family stack quotes “sans-serif”, so the generic fallback is lost.

Quality

Accessibility

  • Rows are <div>s, not a <table>: screen readers get text in order but no column headers.
  • The mobile toggle is a clickable <div> without a button role or keyboard handler.
  • Default label colour #666 on rgba(0,0,0,0.02): check contrast on dark pages.

Security & Privacy

  • No network calls, no storage, no permissions, no third-party libraries.
  • Text is rendered as React text nodes; no dangerouslySetInnerHTML or eval.

Reference

Props

nametypedefaultdescription
propsDatastringfour pattern props (patternType, size, strokeWidth, angle), one per lineProps Data. Enter props data (one per line).
delimiterstring::Delimiter. Characters that separate values.
variantenumXL -- MainVariant. XL -- Main (Desktop) | S -- Main (Mobile Collapsed) | S -- Extended (Mobile Expanded).
fontFontStyleInter, system-ui, sans-serif · 14 · 400 · 1.5Font. Family, size, weight, letter spacing and line height for every cell.
variableAxesbooleanfalseVariable Font. Enable variable font axes.
labelAxesobjectMONO=0, CASL=0, CRSV=0, slnt=0, wght=500, cssFontWeight=500Label Axes. MONO 0–1, CASL 0–1, CRSV 0–1, slnt −15–0, wght 300–1000, cssFontWeight 100–1000 (fallback when the wght axis is not applied); applied to the mobile labels (name:, type:, default:, desc:).
valueAxesobjectMONO=0, CASL=0, CRSV=0, slnt=0, wght=400, cssFontWeight=400Value Axes. MONO 0–1, CASL 0–1, CRSV 0–1, slnt −15–0, wght 300–1000, cssFontWeight 100–1000 (fallback when the wght axis is not applied); applied to the values and the desktop cells.
borderColorcolorrgba(0, 0, 0, 0.04)Border Color. Row borders and the vertical separators.
backgroundColorcolorrgba(0, 0, 0, 0.02)Background. Row background.
hoverBackgroundColorcolorrgba(0, 0, 0, 0.04)Hover Background. Desktop row background on hover.
cardBackgroundColorcolorrgba(0, 0, 0, 0.03)Card Background. The desktop name and default chips, and all four chips on mobile.
labelColorcolor#666Label Color. Color for mobile labels (name:, type:, etc.).
valueColorcolor#111Value Color. Color for actual content values.
hoverColorcolorrgba(0, 0, 0, 0.9)Hover Color. Color applied to both labels and values on hover.

Notes & Tips

  • Write the four columns in order; a missing fourth column shows the word “description”, which is a useful reminder while drafting.
  • Keep defaults short on desktop: the default chip does not wrap (white-space: nowrap).
  • For a mono value column with proportional labels set valueAxes.MONO = 1 and labelAxes.MONO = 0.

Troubleshooting / FAQ

Columns are shifted

A line contains the delimiter inside its text, or uses a different delimiter; check the Delimiter control.

Each row reads the whole line / type / default / description

The lines have no delimiter, so each whole line became the name and the rest fell back to placeholders.

Mobile rows collapse again after an edit

The row components are recreated on each parent render; this resets their open state. Use S -- Extended when rows should stay open.

Table shows “Add Props Data”

Props Data is empty or only blank lines.

Source

Header comment

SC_PropsTable.tsx has no doc comment.

props [REF]

Key excerpt

One text area is the whole API: each line splits on the delimiter into name, type, default and description, with a placeholder word wherever a column is missing.

SC_PropsTable.tsx · lines 108–124 · tsx
    // Parse the text data    const parsedRows = useMemo(() => {        if (!propsData || propsData.trim() === "") return []        return propsData            .split("\n")            .filter((line) => line.trim())            .map((line) => {                const parts = line.split(delimiter).map((p) => p.trim())                return {                    name: parts[0] || "name",                    type: parts[1] || "type",                    default: parts[2] || "default",                    description: parts[3] || "description",                }            })    }, [propsData, delimiter])

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