useFormSurface
How a SchemaForm learns what it is rendering inside. The container declares itself; the form obeys.
Import
ts
import { DEFAULT_FORM_SURFACE, FORM_SURFACE, useFormSurface } from '@core/schema/formSurface'Signature
ts
function useFormSurface(): FormSurface
interface FormSurface {
flat: boolean
footer: boolean
}
const FORM_SURFACE: InjectionKey<FormSurface>
const DEFAULT_FORM_SURFACE: FormSurfaceReturns
| Key | Type | Description |
|---|---|---|
flat | boolean | One flat grid: no group headings, fields reordered by type, uploads and long text on their own full-width row. |
footer | boolean | The form draws its own footer and prepends a Cancel. |
DEFAULT_FORM_SURFACE is { flat: false, footer: false } — what a SchemaForm with no declaring container gets.
Who declares what
| Container | flat | footer |
|---|---|---|
FormPageLayout | true | true |
FormPageLayout with structured | false | true |
FormPageLayout with bare | false | false |
SchemaFormDialog | true | false |
| Anything else | false | false |
FormPageLayout derives both from its own props: flat is !bare && !structured, footer is !bare. structured is how a page keeps its group headings; bare opts out of the card and the form contract entirely, for a page that is a shell rather than a form.
Example
vue
<script setup lang="ts">
import type { FormSurface } from '@core/schema/formSurface'
import { FORM_SURFACE } from '@core/schema/formSurface'
import { provide } from 'vue'
const surface: FormSurface = { flat: true, footer: false }
provide(FORM_SURFACE, surface)
</script>
<template>
<aside class="w-80 border-s p-4">
<slot />
</aside>
</template>Any SchemaForm rendered into that slot now lays itself out flat and leaves the footer to you.
Notes
- This is the reason eighty-odd form pages share one shape. Without it every page would pass
flatandfooterprops down by hand, and they would drift. - A dialog sets
footer: falsebecause it owns aDialogFooter. Nesting the two produces two Cancel buttons, which is exactly the bug this prevents. - The value is plain, not reactive. A surface is a property of the container, and containers do not change what they are mid-life.
useFormSurfacefalls back toDEFAULT_FORM_SURFACErather than throwing, so aSchemaFormdropped anywhere still renders.
Related
- Forms — the form engine.
- Form page layout — declares
footer: true. - Schema form dialog — declares
flat: true. useSchema— wheregroupcomes from, whichflatdrops.