@k8slens/element-components
v3.9.1
Published
Different reusable props using element-component.
Maintainers
Keywords
Readme
@k8slens/element-components
The React primitives Lens's own interface is built from: thin wrappers over HTML elements, with layout, styling and behaviour supplied by $props rather than by stylesheets. Anything built with them inherits the app's spacing scale, colours and theme.
Installation
npm install @k8slens/element-componentsThe model
Ordinary props pass through to the DOM. Props prefixed with $ do not — they are read by plugins:
import { Div, Span, Button } from "@k8slens/element-components";
export const Example = () => (
<Div $flex={{ direction: "vertical", gap: "m" }} $padding="l">
<Span $font={{ size: "xl", bold: true }}>Hello</Span>
<Button $onClick={doTheThing} $tooltip="Does the thing">
Do the thing
</Button>
</Div>
);Elements
A, Button, Canvas, ClickableDiv, ClickableLi, Code, Dialog, Div, Form, H1–H6, I, Img, Input, Label, Li, Nav, Ol, P, Pre, Span, Svg, Table, TBody, Td, TextArea, Th, Tr, Ul.
The size scale
Anything taking a size takes a t-shirt size rather than pixels: zero, xxxs, xxs, xs, s, m, l, xl, xxl, 3xl … 11xl. One step is 4px.
The $props
Layout
: $flex, $flexChild, $grid, $area, $areaContent, $offset, $offsetChildren, $block, $displayContents
The box
: $size, $width, $height, $margin, $padding, $border, $boxShadow, $outline, $overflow
Appearance
: $color, $backgroundColor, $font, $textAlign, $gradient, $tint, $grayscale, $faded, $transition, $className, $style
Position and overlays
: $relative, $absolute, $fixed, $anchor, $anchoredAt, $floating, $popover, $invisibleBackdrop
Interaction
: $onClick, $onDoubleClick, $onMiddleClick, $onRightClick, $onOnlyMouseClick, $onOutsideClick, $cursor, $enabled, $disabled
Stateful behaviour
: $tooltip, $hoverable, $hoverableByDragging, $focusable, $draggable, $droppable, $dropDownMenu
Visibility and escape hatches
: $hidden, $visuallyHidden, $noPointerEvents, $ref, $wrapper
The types are the reference for each one's values; the sections below cover the ones whose shape is easy to get wrong.
Colour comes from the theme
Named roles, not literals. Text takes textDefault, textMuted or textHighlight; backgrounds take backgroundPrimary, backgroundSecondary or backgroundPrimaryDimmed; borders take borderPrimary. Status and emphasis have roles of their own (primary, success, notice, warning, critical, link, code), and the nominal palette (grey10…grey100, white, inherit, transparent) is available, but a role survives a change to the palette where a nominal grey does not.
<Span $color="textMuted" />
<Div $backgroundColor="backgroundPrimary" />Borders
color is a theme role or nominal colour, width is on the t-shirt scale, and radius is one of zero, s, m, ml, l, 50, full (or true for the default):
<Div $border={{ color: "borderPrimary", width: "xxs", radius: "m" }} $boxShadow />Sizes accept a range
The range object's own field is named after its prop — size for $size, height for $height, width for $width — alongside min and max.
<Div $width="full" $height={{ min: "m", height: "l", max: "xl" }} />$onClick, not onClick
$onClick also activates on Enter, and on Space when the element itself is focused, and it respects $enabled. Plain onClick does neither, which is the usual cause of a control a keyboard user cannot reach.
Passing $props through your own components
Extend the element's props and spread the rest onto the root element, so callers can lay your component out:
import { Div, type DivProps } from "@k8slens/element-components";
interface StatusBadgeProps extends DivProps {
readonly status: "success" | "error" | "pending";
}
export const StatusBadge = ({ status, ...rest }: StatusBadgeProps) => (
<Div $flex={{ direction: "horizontal", gap: "s" }} {...rest}>
{status}
</Div>
);Prop types are exported per element: DivProps, ButtonProps, and so on.
Styles and registration
The stylesheets travel with the Feature: lens-package-build compiles each one
into a stylesheet injectable the Feature registers, and the application applies
them while the Feature is registered. There is nothing to import for them.
The package exports that Feature, which the application registers:
import { elementComponentFeature } from "@k8slens/element-components";An extension does not register it — the host already has. A unit test that renders these components does need it registered in its container.
