Vitus Labs
Elements

Elements

Base UI primitives for building React interfaces — Element, Text, List, Overlay, and Portal.

@vitus-labs/elements provides the foundational building blocks for the UI system. Every higher-level component (rocketstyle, coolgrid) is built on top of these primitives.

Installation

npm install @vitus-labs/elements

Components

ComponentPurpose
ElementCore 3-section flex layout (beforeContent / content / afterContent)
TextSemantic text rendering primitive
ListData-driven list renderer with extended item props
OverlayPositioning system for dropdowns, tooltips, popovers, modals
PortalDOM portal for rendering outside the component hierarchy
UtilNon-rendering wrapper that injects className/style into children

Responsive Values

All layout props across Element, Text, and List support responsive values in three formats:

// Single value
<Element gap={10} />

// Array (mobile-first, one per breakpoint)
<Element gap={[8, 12, 16, 20]} />

// Breakpoint object
<Element gap={{ xs: 8, md: 12, lg: 16 }} />

CSS Props

Components accept CSS via ExtendCss in multiple formats:

// Template literal
<Element css={css`padding: 16px;`} />

// Callback (access to css function)
<Element css={(css) => css`
  padding: 16px;
  background: ${(props) => props.theme.bg};
`} />

// Responsive
<Element css={{
  xs: `padding: 8px;`,
  md: `padding: 16px;`,
}} />

Try It Live

function FlexDemo() {
const [direction, setDirection] = React.useState('row')
const [gap, setGap] = React.useState(12)
const [alignItems, setAlignItems] = React.useState('center')

const items = ['Element A', 'Element B', 'Element C']

return (
  <div style={{ fontFamily: 'system-ui' }}>
    <div style={{ display: 'flex', gap: 16, marginBottom: 16, flexWrap: 'wrap' }}>
      <label style={{ fontSize: 13 }}>
        Direction:
        <select value={direction} onChange={(e) => setDirection(e.target.value)}
          style={{ marginLeft: 4, padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}>
          <option value="row">inline (row)</option>
          <option value="column">rows (column)</option>
        </select>
      </label>
      <label style={{ fontSize: 13 }}>
        Gap: {gap}px
        <input type="range" min={0} max={32} value={gap}
          onChange={(e) => setGap(Number(e.target.value))}
          style={{ marginLeft: 4 }} />
      </label>
      <label style={{ fontSize: 13 }}>
        Align:
        <select value={alignItems} onChange={(e) => setAlignItems(e.target.value)}
          style={{ marginLeft: 4, padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}>
          <option value="flex-start">top / left</option>
          <option value="center">center</option>
          <option value="flex-end">bottom / right</option>
          <option value="stretch">stretch</option>
        </select>
      </label>
    </div>
    <div style={{
      display: 'flex',
      flexDirection: direction,
      gap: gap,
      alignItems: alignItems,
      padding: 16,
      borderRadius: 8,
      border: '2px dashed #ccc',
      minHeight: 120,
    }}>
      {items.map((item, i) => (
        <div key={i} style={{
          padding: '12px 20px',
          borderRadius: 6,
          background: ['#dbeafe', '#fce7f3', '#d1fae5'][i],
          color: ['#1e40af', '#be185d', '#065f46'][i],
          fontWeight: 500,
          fontSize: 14,
        }}>
          {item}
        </div>
      ))}
    </div>
  </div>
)
}

render(<FlexDemo />)

Quick Example

import { Element, Text, List } from '@vitus-labs/elements'

function Card({ icon, title, items }) {
  return (
    <Element
      tag="article"
      direction="rows"
      gap={16}
      css={(css) => css`
        padding: 24px;
        border-radius: 8px;
        border: 1px solid #e0e0e0;
      `}
    >
      <Element beforeContent={icon} gap={8} alignY="center">
        <Text tag="h3">{title}</Text>
      </Element>

      <List
        rootElement
        component={({ children }) => <Text>{children}</Text>}
        data={items}
        valueName="children"
        gap={4}
        direction="rows"
      />
    </Element>
  )
}

Util

A non-rendering wrapper that injects className and style into its single child without adding any DOM nodes:

import { Util } from '@vitus-labs/elements'

<Util className="highlight" style={{ color: 'red' }}>
  <span>Styled child</span>
</Util>
// Renders: <span class="highlight" style="color: red;">Styled child</span>
PropTypeDescription
childrenReactNodeSingle child element
classNamestring | string[]CSS class(es) to inject (arrays are joined)
styleobjectInline styles to merge

Uses render() from @vitus-labs/core to clone the child with the injected props.

VLStatic Interface

Every component in this package implements the VLStatic interface:

interface VLStatic {
  displayName?: string
  pkgName?: string
  VITUS_LABS__COMPONENT?: `@vitus-labs/${string}`
}

This enables identification and metadata access across the ecosystem. For example, rocketstyle uses VITUS_LABS__COMPONENT to verify that components originate from @vitus-labs/elements.

Iterator Types

These types power the data-driven rendering in List (and can be imported for custom use):

ExtendedProps

Positional metadata injected into each rendered item:

type ExtendedProps = {
  index: number    // 0-based array index
  position: number // 1-based position (index + 1)
  first: boolean   // true if position === 1
  last: boolean    // true if position === length
  odd: boolean     // true if position is odd (1, 3, 5...)
  even: boolean    // true if position is even (2, 4, 6...)
}

ObjectValue

Data object shape for object arrays in List's data prop:

type ObjectValue = Partial<{
  id: SimpleValue       // Fallback key (priority 1)
  key: SimpleValue      // Fallback key (priority 2)
  itemId: SimpleValue   // Fallback key (priority 3)
  component: ElementType // Per-item component override
}> & Record<string, unknown>

The component property is consumed by the iterator and not passed to the rendered component. All other properties are spread as props.

PropsCallback

Type for itemProps and wrapProps — can be a static object or a function receiving item data and positional metadata:

type PropsCallback =
  | Record<string, unknown>                              // Static props
  | ((
      itemProps: Record<string, unknown> | ObjectValue,  // Item data
      extendedProps: ExtendedProps,                       // Positional metadata
    ) => Record<string, unknown>)

IteratorProps

Full props type for the internal Iterator component (used by List):

type IteratorProps = Partial<{
  children: ReactNode
  data: Array<string | number | ObjectValue | null>
  component: ElementType
  valueName: string
  wrapComponent: ElementType
  itemProps: PropsCallback
  wrapProps: PropsCallback
  itemKey: string | ((item, index: number) => string | number)
}>

Exports

import {
  Element,
  Text,
  List,
  Overlay,
  Portal,
  Util,
  Provider,
  useOverlay,
  OverlayProvider,
} from '@vitus-labs/elements'

import type {
  ElementProps,
  TextProps,
  ListProps,
  OverlayProps,
  PortalProps,
  UtilProps,
  UseOverlayProps,
  IteratorProps,
  AlignX,
  AlignY,
  Direction,
  Content,
  ExtendCss,
  Responsive,
  ResponsiveBoolType,
  VLStatic,
  VLForwardedComponent,
  VLComponent,
  PropsCallback,
  ObjectValue,
  ExtendedProps,
  ElementType,
} from '@vitus-labs/elements'

On this page