npx facet-rbxts add separatorCopies ui/separator.tsx, plus lib/utils.ts. Needs @facet-ui/react-variants and
@lattice-ui/react-runtime.
import { Separator } from "../shared/ui/separator";
<Separator /><Separator orientation="vertical" />import React from "@rbxts/react";import { Label } from "../ui/label";import { Separator } from "../ui/separator";import { MODE } from "../facet-mode";
export function Separators() { return ( <frame className="flex-col gap-3 w-full h-fit"> <Label Text="Inventory" /> <Separator /> {/* A vertical separator takes its height from the row, so the row states one — `h-full` cannot measure a parent that is still hugging. */} <frame className="flex-row items-center gap-3 w-full h-5"> <Label Text="Weapons" /> <Separator orientation="vertical" /> <Label Text="Armor" /> <Separator orientation="vertical" /> <Label Text="Potions" /> </frame> </frame> );}import { fv, type VariantProps } from "@facet-ui/react-variants";import { getPassthroughProps, type PassthroughProps, React } from "@lattice-ui/react-runtime";import { cn } from "~/lib/utils";
// Both axes are concrete on each orientation, so this needs no `AutomaticSize`.// `h-px` is one pixel, not a spacing step.export const separatorVariants = fv("shrink-0 bg-border", { variants: { orientation: { horizontal: "w-full h-px", vertical: "h-full w-px", }, }, defaultVariants: { orientation: "horizontal", },});
export type SeparatorProps = VariantProps<typeof separatorVariants> & PassthroughProps<Frame>;
const OWN_PROPS = ["orientation", "className"] as const;
// No `BackgroundTransparency: 1` here — unlike every other component, the// background *is* the separator.const NEUTRAL_PROPS = { BorderSizePixel: 0,};
export function Separator(props: SeparatorProps) { const passthrough = getPassthroughProps<Frame>(props, OWN_PROPS);
return ( <frame className={cn( separatorVariants({ orientation: props.orientation, className: props.className, }), )} {...NEUTRAL_PROPS} {...passthrough} /> );}Renders a Frame. Unknown props forward onto it and are type-checked against it, so a prop Frame does not accept is a compile error.
Props
| Prop | Type | Description |
|---|---|---|
| orientation | "horizontal" | "vertical" | Which axis is one pixel. Defaults to horizontal. |
| className | ClassName | Threaded into the recipe's className slot inside the component. A class written at a Vela-compiled call site never reaches it — see Overriding from the call site. |
Everything else is forwarded onto the Frame. There is no Text and no children — this is a
frame with a colour.
The recipe
export const separatorVariants = fv("bg-border", { variants: { orientation: { horizontal: "w-full h-px", vertical: "h-full w-px", }, }, defaultVariants: { orientation: "horizontal" },});Both axes are concrete on each orientation — w-full h-px, h-full w-px — so this is the one
component in the registry that needs no automatic sizing at all. h-px is one literal pixel, not a
spacing step.
h-full on the vertical orientation means the parent has to have a resolved height. Inside a
flex-row container that hugs its content, that is not automatic — give the container a height. Not
the separator: a className at the call site resolves to Size there and the recipe, which names
both axes, overwrites it. See
overriding from the call site.
The one component that keeps its background
Every other Facet component clears Roblox’s defaults before styling:
const NEUTRAL_PROPS = { BorderSizePixel: 0,};No BackgroundTransparency: 1 here, unlike everywhere else — the background is the separator.
bg-border is the whole visual, and clearing it would leave a one-pixel invisible frame.