Components

One design system, drawn natively everywhere

Every OpenVibe component is described by what it is: its parts, the tokens they wear, its states, and how it reads to a screen reader. The web draws it with the kit; an Android or iOS app draws the same component with its own views, so an app is never a web page in a frame.

Fold

A card that opens and closes, for what is read once: setup, extras, details, the danger zone. Closed unless told.

Put this room on your site · two ways

Copy the embed code, or link to the room.

Parts and their tokens

  • summaryminHeightsize.tapweighttype.weight.boldthe title, a muted word after it, a chevron that turns
  • bodypaddingspace.md

How it behaves

Role
disclosure (details/summary)
Props
id title* meta open tone * required
States
closed · open · focused
Name
its title
Keys
Enter or Space opens and closes
Target
44 px
Phone
full width
Computer
in its column

Code

Jetpack Compose, on the theme file from Tokens (Android): Material 3 roles for colour, OvScale for sizes.

// OpenVibe kit for Jetpack Compose: add the theme file from openvibe.design/tokens (Android) and wrap the app in
// MaterialTheme(colorScheme = if (isSystemInDarkTheme()) VibeDarkColorScheme else VibeLightColorScheme) { … }
enum class OvKind { Primary, Quiet, Danger }
enum class OvNoticeKind { Ok, Info, Warn, Error }

@Composable
fun OvFold(title: String, meta: String? = null, initiallyOpen: Boolean = false, content: @Composable () -> Unit) {
    var open by rememberSaveable { mutableStateOf(initiallyOpen) }
    Surface(shape = RoundedCornerShape(OvScale.RadiusMd)) {
        Column {
            Row(Modifier.fillMaxWidth().heightIn(min = OvScale.SizeTap).clickable(onClickLabel = if (open) "Close" else "Open") { open = !open }.padding(horizontal = OvScale.SpaceMd),
                verticalAlignment = Alignment.CenterVertically) {
                Text(title, Modifier.weight(1f), fontWeight = FontWeight.Bold)
                if (meta != null) Text(meta, color = MaterialTheme.colorScheme.onSurfaceVariant)
                Icon(Icons.Default.ExpandMore, null, Modifier.rotate(if (open) 180f else 0f))
            }
            AnimatedVisibility(open) { Box(Modifier.padding(OvScale.SpaceMd)) { content() } }
        }
    }
}

Shared interfaces

Web, Android and iOS definitions for the navigation, composer, sheets, settings and motion used across OpenVibe. See the whole registry, or read it as JSON at /api/v1/components.

Kit documents: screens as data

A screen can be sent as a tree of these components, for example { "type": "rail", "children": [{ "type": "card", … }] }. Every OpenVibe client renders the same document with its own views, so a screen can change without an app release (the server-driven UI pattern of Airbnb and DivKit). Documents are checked strictly: known components and props only, typed values, which children each takes, a size limit, and https or same-site links.

The specs as JSON The tokens they wear