useTypography
The type scale. Three presets, each rewriting the seven --sa-text-* variables the whole app sizes text with.
vue
<script setup lang="ts">
import { useTypography } from '@core/theme/useTypography'
import { Button } from '@shared/components/ui/button'
import { onBeforeUnmount } from 'vue'
const PRESETS = ['compact', 'default', 'comfortable'] as const
const { setScale, currentPreset } = useTypography()
const original = currentPreset.value
onBeforeUnmount(() => setScale(original))
</script>
<template>
<div class="flex flex-col gap-5">
<div class="flex flex-wrap items-center gap-2">
<Button
v-for="preset in PRESETS"
:key="preset"
size="sm"
variant="outline"
:aria-pressed="currentPreset === preset"
@click="setScale(preset)"
>
{{ preset }}
</Button>
</div>
<div class="flex flex-col gap-2 rounded-lg border border-border p-4">
<p class="sa-text-3xl font-semibold">
Quarterly revenue
</p>
<p class="sa-text-base">
Every size on this card comes from a <code>--sa-text-*</code> variable.
</p>
<p class="sa-text-sm text-muted-foreground">
Nothing here sets a pixel size of its own.
</p>
<p class="sa-text-xs text-muted-foreground">
Active preset: {{ currentPreset }}
</p>
</div>
</div>
</template>Import
ts
import { useTypography } from '@core/theme/useTypography'Signature
ts
function useTypography(): {
setScale: (preset: TypographyPreset) => void
setToken: (name: TextSize, value: string) => void
resetScale: () => void
currentPreset: Readonly<Ref<TypographyPreset>>
}TypographyPreset is 'compact' | 'default' | 'comfortable'. TextSize is 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl'.
Returns
| Member | Type | Description |
|---|---|---|
setScale | (preset) => void | Writes all seven sizes and records the preset. |
setToken | (name, value) => void | Overrides one size, e.g. setToken('base', '1.0625rem'). |
resetScale | () => void | Back to default. |
currentPreset | Readonly<Ref<TypographyPreset>> | The active preset. |
The presets
Each preset is a base size in pixels and a factor. The seven sizes derive as base × factor ** offset, with base at offset 0, xs two steps down and 3xl four steps up.
| Preset | Base | Factor |
|---|---|---|
compact | 13px | 1.2 |
default | 16px | 1.2 |
comfortable | 16px | 1.333 |
Because base is offset 0, two presets sharing a base leave --sa-text-base where it is and move everything around it.
Example
vue
<script setup lang="ts">
import { useTypography } from '@core/theme/useTypography'
const { setScale, setToken, resetScale, currentPreset } = useTypography()
</script>
<template>
<div class="flex flex-wrap items-center gap-3">
<button type="button" @click="setScale('compact')">
Compact
</button>
<button type="button" @click="setScale('comfortable')">
Comfortable
</button>
<button type="button" @click="setToken('base', '1.0625rem')">
Nudge the base size
</button>
<button type="button" @click="resetScale()">
Reset
</button>
<span>{{ currentPreset }}</span>
</div>
</template>Notes
- Nothing is applied on the first call. The preset is stored in
config.typographyScaleand the config wiring replays it at boot, so this composable does not race it. setTokenaccepts the seven known size keys only. A typo would write a--sa-text-*variable nothing reads and fail with no error, so the type is the guard.setTokenwrites an inline value on:root, which outranks whateversetScalewrote. A latersetScaleoverwrites it again.- Both writers no-op when there is no
document.
Related
useTheme— the preset is part of a theme snapshot.useDensity— the spacing equivalent.- Theming — every token.