threlte-uikit wraps @pmndrs/uikit in a declarative syntax for use with Threlte.
npm i threlte-uikit
| Import path | Contents |
|---|---|
threlte-uikit |
Core primitives (Container, Text, etc.) |
threlte-uikit/kit |
Kit component library |
threlte-uikit/horizon |
Horizon component library |
threlte-uikit/lucide |
Lucide icon components |
<script>
import { T } from '@threlte/core'
import { interactivity } from '@threlte/extras'
import { Container, Text } from 'threlte-uikit'
interactivity()
</script>
<T.Group>
<Container
padding={10}
backgroundColor="#ccc"
>
<Text text="Hello uikit!" />
</Container>
</T.Group>The component instance may be accessed via the ref property.
<Container bind:ref>...</Container>These components map 1:1 to the @pmndrs/uikit primitives. See the uikit component docs for the full property reference.
| Component | Docs |
|---|---|
Container |
docs |
Fullscreen |
docs |
Image |
docs |
Text |
docs |
SVG |
docs |
Content |
docs |
Input |
docs |
Textarea |
docs |
Video |
docs |
Set overflow="scroll" on any Container to make it scrollable. Requires interactivity() to be active.
<Container
overflow="scroll"
height={200}
flexDirection="column"
>
{#each items as item}
<Text text={item} />
{/each}
</Container>Invoke the Threlte interactivity plugin in the same component or a parent to enable pointer events. All events supported by interactivity are supported.
<Container
onclick={() => console.log('clicked')}
onpointerenter={() => console.log('entered')}
onpointerleave={() => console.log('left')}
>
<Text text="I am a button" />
</Container>hover and active conditional properties also require interactivity():
<Container
backgroundColor="red"
hover={{ backgroundColor: 'purple' }}
active={{ backgroundColor: 'blue' }}
>
...
</Container>Import from threlte-uikit/kit. These are unstyled, accessible components built on the uikit primitives, inspired by shadcn/ui.
| Component | Description |
|---|---|
Alert |
Alert banner with icon, title, and description slots |
AlertIcon |
Icon slot for Alert |
AlertTitle |
Title slot for Alert |
AlertDescription |
Description slot for Alert |
Accordion |
Collapsible accordion container |
AccordionItem |
Individual accordion section |
AccordionTrigger |
Clickable accordion header |
AccordionContent |
Accordion body content |
Avatar |
Circular image avatar |
Badge |
Small label badge |
Button |
Pressable button |
Card |
Card container |
CardHeader |
Card header section |
CardTitle |
Card title |
CardDescription |
Card description |
CardContent |
Card body content |
CardFooter |
Card footer section |
Checkbox |
Checkbox with checked/unchecked state |
KitInput |
Single-line text input |
KitTextarea |
Multi-line text input |
Label |
Form label |
Progress |
Linear progress bar |
RadioGroup |
Radio group container |
RadioGroupItem |
Individual radio item |
Separator |
Horizontal divider |
Skeleton |
Loading skeleton placeholder |
Slider |
Range slider |
Switch |
Toggle switch |
Tabs |
Tab container |
TabsList |
Tab navigation bar |
TabsTrigger |
Individual tab button |
TabsContent |
Tab panel content |
Toggle |
Pressable toggle button |
ToggleGroup |
Group of toggle buttons |
ToggleGroupItem |
Individual item in a ToggleGroup |
Import from threlte-uikit/horizon. A fully themed component set that supports light and dark mode automatically.
| Component | Description |
|---|---|
Panel |
Rounded card container |
Button |
Button with primary, secondary, tertiary, negative variants |
Badge |
Label badge with primary, secondary, positive, negative variants |
Avatar |
Circular image avatar (sm, md, lg) |
Checkbox |
Styled checkbox |
Toggle |
Styled toggle switch |
Slider |
Styled range slider |
ProgressBar |
Linear progress indicator |
RadioGroup |
Styled radio group |
RadioGroupItem |
Styled radio item |
Input |
Styled text input with optional icon |
InputField |
Labeled input field |
Dropdown |
Styled dropdown |
DropdownButton |
Dropdown trigger button |
DropdownTextValue |
Displays the selected dropdown value |
DropdownList |
Dropdown option list |
DropdownListItem |
Individual dropdown option |
IconIndicator |
Status indicator dot (none, good, poor, bad) |
Divider |
Horizontal rule |
Import from threlte-uikit/lucide. Renders any Lucide icon as a uikit element.
<script>
import { Icon, SearchIcon } from 'threlte-uikit/lucide'
</script>
<Icon
is={SearchIcon}
width={24}
height={24}
/>All Lucide icon components are re-exported from this subpath.
Overrides default properties for all uikit components within the calling component's subtree.
let defaultProps = $state({ margin: 10 })
provideDefaultProperties(() => defaultProps)Provides custom font families to the subtree. See the uikit custom fonts guide for how to generate compatible font JSON files.
provideFontFamilies({
roboto: {
light: 'url-to-json',
medium: 'url-to-json',
bold: 'url-to-json',
},
})threlte-uikit inherits dark mode from @pmndrs/uikit via the isDarkMode signal. Horizon components automatically respond to dark/light mode changes.
<script>
import { isDarkMode } from 'threlte-uikit'
</script>
<div>
{isDarkMode.current ? 'Light mode' : 'Dark mode'}
</div>When using CameraControls or OrbitControls from @threlte/extras, they are automatically detected by threlte-uikit and disabled during UI pointer interactions such as drags and scrolls — no extra configuration required.
<script>
import { CameraControls, interactivity } from '@threlte/extras'
import { Container } from 'threlte-uikit'
interactivity()
</script>
<CameraControls />
<Container>
<!-- Sliders, scrollable containers, etc. automatically disable CameraControls while active -->
</Container>