Appearance
Prop defaults
The library lets you set prop values once for the whole app instead of repeating them in every template or writing local wrappers around components.
Priority
From strongest to weakest:
- a prop passed to the component explicitly;
- the default for this component (
SButton: { size: 'lg' }); - the global default (
global: { size: 'lg' }); - the component's own default.
App level
ts
import { createApp } from 'vue'
import { createSUI } from '@smalt-ui/core'
import '@smalt-ui/core/styles.css'
createApp(App).use(
createSUI({
defaults: {
global: { size: 'sm' },
SButton: { variant: 'outline' },
SInput: { clearable: true },
},
}),
)Subtree level
ConfigProvider sets defaults for its part of the tree, for example a compact panel inside a regular app:
vue
<script setup lang="ts">
import { ConfigProvider } from '@smalt-ui/core'
</script>
<template>
<ConfigProvider :defaults="{ global: { size: 'sm' } }">
<SidebarFilters />
</ConfigProvider>
</template>Nested providers override outer ones.
In Nuxt
ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@smalt-ui/nuxt'],
sui: {
defaults: {
global: { size: 'sm' },
SButton: { variant: 'outline' },
},
},
})What counts as "passed explicitly"
A prop counts as explicit if it is present in the markup with a value, in any casing (size="lg" and :size="value", icon-right and iconRight).
undefined does not count as explicit. This matters for wrapper components where the prop is optional: in the markup below the button gets size from the configuration until the wrapper is given its own size, which is the same behavior as having no attribute at all.
vue
<template>
<!-- props.size === undefined → the ConfigProvider/preset default applies -->
<SButton :size="props.size">{{ label }}</SButton>
</template>Configuration layers
Defaults stack in layers and per prop: preset → plugin defaults or the Nuxt option → ConfigProvider in a subtree. Each layer refines the previous one instead of replacing it entirely, so a ConfigProvider added for one locale or one default does not cancel the app configuration.
Styling is configured with defaults too
Appearance that consumers would otherwise have to override in CSS is exposed as props, so it can be set once for the whole app:
ts
app.use(
createSUI({
defaults: {
// square corners on all controls and panels at once
global: { square: true },
// filled buttons without a shadow
SButton: { flat: true },
// inputs without a floating label and without the clear button
SInput: { floatingLabel: false, clearable: false },
},
}),
)global applies to every component that declares the prop: square exists on all controls and on floating panels (dropdown lists, menus, popovers, calendars), size on all components affected by interface density. floatingLabel in global turns on the floating label only for fields that can render it (SInput, STextarea, SSelect, date and time fields and pickers, SColorField). The rest (SNumberField, SAutocomplete, SPinInput, SSlider, groups) keep their label on top.