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/elementsComponents
| Component | Purpose |
|---|---|
| Element | Core 3-section flex layout (beforeContent / content / afterContent) |
| Text | Semantic text rendering primitive |
| List | Data-driven list renderer with extended item props |
| Overlay | Positioning system for dropdowns, tooltips, popovers, modals |
| Portal | DOM portal for rendering outside the component hierarchy |
| Util | Non-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>| Prop | Type | Description |
|---|---|---|
children | ReactNode | Single child element |
className | string | string[] | CSS class(es) to inject (arrays are joined) |
style | object | Inline 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'