v2.7.1

Theme

A headless component for theming its child components.

Usage

The Theme component allows you to override default slot classes and props of all child components without modifying each one individually. It uses Vue's provide / inject mechanism under the hood, so the overrides apply at any depth.

The Theme component doesn't render any HTML element, it only provides theme overrides to its children.

Slot classes

Use the b24ui prop to override slot classes of descendant components. Keys are component names (camelCase) and values are their slot class overrides.

<template>
  <B24Theme
    :b24ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex items-center gap-2">
      <B24Button label="Button" color="air-primary-success" />
      <B24Button label="Button" color="air-secondary-accent-1" />
      <B24Button label="Button" color="air-boost" />
    </div>
  </B24Theme>
</template>

Prop defaults Soon

Use the props prop to override the default value of any prop on descendant components. Each key maps to a partial of that component's props.

<script setup lang="ts">
import RocketIcon from '@bitrix24/b24icons-vue/outline/RocketIcon'
import AiStarsIcon from '@bitrix24/b24icons-vue/outline/AiStarsIcon'
</script>

<template>
  <B24Theme
    :props="{
      button: { color: 'air-boost', size: 'lg' },
      tooltip: { delayDuration: 0, arrow: true }
    }"
  >
    <div class="flex items-center gap-2">
      <B24Tooltip text="Inherits delayDuration from theme">
        <B24Button label="Hover me" />
      </B24Tooltip>
      <B24Button label="With icon" :icon="RocketIcon" />
      <B24Button :icon="AiStarsIcon" square />
    </div>
  </B24Theme>
</template>
Explicit props on a component (e.g. <B24Button color="air-primary" />) always win over <B24Theme :props>. Theme defaults only apply when the prop wasn't passed explicitly.

Examples

Multiple components

Use different keys in b24ui or props to theme multiple component types at once.

<template>
  <B24Theme
    :props="{
      button: { color: 'air-secondary-accent-1', size: 'lg' },
      input: { size: 'lg' },
      select: { size: 'lg' }
    }"
    :b24ui="{
      button: {
        base: 'rounded-full'
      },
      input: {
        base: 'rounded-full'
      },
      select: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex items-center gap-2">
      <B24Button label="Button" />
      <B24Input placeholder="Search..." />
      <B24Select placeholder="Select" :items="['Item 1', 'Item 2', 'Item 3']" />
    </div>
  </B24Theme>
</template>

Nested themes

Nest multiple Theme components to compose overrides. The innermost Theme takes precedence, while unoverridden keys are inherited from the outer Theme.

<template>
  <B24Theme
    :b24ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex flex-col items-start gap-4 border border-muted p-4 rounded-lg">
      <div class="flex items-center gap-2">
        <B24Button label="Outer theme" />
        <B24Button label="Outer theme" color="air-secondary-accent-1" />
      </div>

      <B24Theme
        :b24ui="{
          button: {
            base: 'font-black uppercase'
          }
        }"
      >
        <div class="border border-muted p-4 rounded-lg">
          <div class="flex items-center gap-2">
            <B24Button label="Inner theme" />
            <B24Button label="Inner theme" color="air-secondary-accent-1" />
          </div>
        </div>
      </B24Theme>
    </div>
  </B24Theme>
</template>

Explicit priority

Explicitly setting any prop (including b24ui) on an individual component always takes priority over the Theme component.

<template>
  <B24Theme
    :b24ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex items-center gap-2">
      <B24Button label="Themed" />
      <B24Button label="Overridden" :b24ui="{ base: 'rounded-none' }" />
    </div>
  </B24Theme>
</template>

Deep propagation

The overrides are available to all descendant components regardless of how deeply nested they are.

<script setup lang="ts">
import MyButton from './MyButton.vue'
</script>

<template>
  <B24Theme
    :b24ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <B24Card :b24ui="{ body: 'flex items-center gap-2 sm:flex-row flex-col' }">
      <B24Button label="Direct child" />
      <MyButton />
    </B24Card>
  </B24Theme>
</template>
In this example, MyButton is a custom component that renders a B24Button internally. The theme overrides still apply because they propagate through the entire component tree.

Form components

Use the Theme component to apply consistent styling across a group of form components.

Your public display name.

Used for notifications.

A short description about yourself.

<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@bitrix24/b24ui-nuxt'

const schema = z.object({
  name: z.string().min(2, 'Too short'),
  email: z.email('Invalid email'),
  bio: z.string().optional()
})

type Schema = z.output<typeof schema>

const state = reactive<Partial<Schema>>({
  name: 'John Doe',
  email: 'john@example.com',
  bio: undefined
})

const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({ title: 'Saved', description: 'Your profile has been updated.', color: 'air-primary-success' })
  console.log(event.data)
}
</script>

<template>
  <B24Theme
    :props="{
      input: { size: 'lg' },
      textarea: { color: 'air-primary-success' }
    }"
    :b24ui="{
      formField: {
        root: 'flex max-sm:flex-col justify-between gap-4',
        wrapper: 'w-full sm:max-w-80'
      }
    }"
  >
    <B24Form :schema="schema" :state="state" class="space-y-4 w-full" @submit="onSubmit">
      <B24FormField label="Name" name="name" description="Your public display name.">
        <B24Input v-model="state.name" />
      </B24FormField>

      <B24FormField label="Email" name="email" description="Used for notifications.">
        <B24Input v-model="state.email" type="email" />
      </B24FormField>

      <B24FormField label="Bio" name="bio" description="A short description about yourself.">
        <B24Textarea v-model="state.bio" placeholder="Tell us about yourself" />
      </B24FormField>

      <div class="flex justify-end">
        <B24Button type="submit">
          Save changes
        </B24Button>
      </div>
    </B24Form>
  </B24Theme>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import * as z from 'zod'
import type { FormSubmitEvent } from '@bitrix24/b24ui-nuxt'

const schema = z.object({
  name: z.string().min(2, 'Too short'),
  email: z.email('Invalid email'),
  bio: z.string().optional()
})

type Schema = z.output<typeof schema>

const state = reactive<Partial<Schema>>({
  name: 'John Doe',
  email: 'john@example.com',
  bio: undefined
})

const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({ title: 'Saved', description: 'Your profile has been updated.', color: 'air-primary-success' })
  console.log(event.data)
}
</script>

<template>
  <B24Theme
    :props="{
      input: { size: 'lg' },
      textarea: { color: 'air-primary-success' }
    }"
    :b24ui="{
      formField: {
        root: 'flex max-sm:flex-col justify-between gap-4',
        wrapper: 'w-full sm:max-w-80'
      }
    }"
  >
    <B24Form :schema="schema" :state="state" class="space-y-4 w-full" @submit="onSubmit">
      <B24FormField label="Name" name="name" description="Your public display name.">
        <B24Input v-model="state.name" />
      </B24FormField>

      <B24FormField label="Email" name="email" description="Used for notifications.">
        <B24Input v-model="state.email" type="email" />
      </B24FormField>

      <B24FormField label="Bio" name="bio" description="A short description about yourself.">
        <B24Textarea v-model="state.bio" placeholder="Tell us about yourself" />
      </B24FormField>

      <div class="flex justify-end">
        <B24Button type="submit">
          Save changes
        </B24Button>
      </div>
    </B24Form>
  </B24Theme>
</template>
<B24FormField>, <B24FieldGroup> and <B24AvatarGroup> keep precedence over <B24Theme :props> for size, color and highlight. Validation errors also force the error color over any theme value.

Prose components

Use the prose namespace to theme typography components. Keys are nested under prose (e.g. prose.p, prose.code).

Getting started

This is a paragraph with a tighter typographic scale applied through the Theme component.

  • First item
  • Second item
  • Third item

The spacing and font sizes are smaller than the defaults, making it ideal for compact content areas.

<script setup lang="ts">
const b24ui = {
  prose: {
    p: { base: 'my-2.5 text-sm/6' },
    li: { base: 'my-0.5 text-sm/6' },
    ul: { base: 'my-2.5' },
    ol: { base: 'my-2.5' },
    h1: { base: 'text-xl mb-4' },
    h2: { base: 'text-lg mt-6 mb-3' },
    h3: { base: 'text-base mt-4 mb-2' },
    h4: { base: 'text-sm mt-3 mb-1.5' },
    code: { base: 'text-xs' },
    pre: { root: 'my-2.5', base: 'text-xs/5' },
    table: { root: 'my-2.5' },
    hr: { base: 'my-5' }
  }
}

const value = `## Getting started

This is a paragraph with a **tighter typographic scale** applied through the \`Theme\` component.

- First item
- Second item
- Third item

> The spacing and font sizes are smaller than the defaults, making it ideal for compact content areas.`
</script>

<template>
  <B24Theme :b24ui="b24ui">
    <MDC :value="value" />
  </B24Theme>
</template>

API

Props

Prop Default Type
props ThemeDefaults

Per-component prop defaults that flow through useComponentProps to every descendant. Each key maps to a partial of that component's props.

b24ui ThemeUI

Per-component slot class overrides (flat shorthand for :props.<name>.b24ui).

Slots

Slot Type
default{}