Custom styling
Texaryn’s default React widgets render semantic HTML. Wrap FormRoot in your
own styling scope to change the appearance without replacing the schema
adapter, form runtime, or widget registry.
<FormProvider value={form.runtime}> <EmotionForm> <FormRoot registry={createDefaultRegistry()} /> </EmotionForm></FormProvider>The wrapper owns styles. The default registry continues to own labels, input bindings, validation messages, and array actions. For controls that need different markup or behavior, register custom widgets instead.
Bootstrap 5
Section titled “Bootstrap 5”In an application using @texaryn/react, add the widget package and CSS:
pnpm add @texaryn/react-bootstrap bootstrapimport { createBootstrapRegistry } from '@texaryn/react-bootstrap'import 'bootstrap/dist/css/bootstrap.min.css'
const registry = createBootstrapRegistry()Pass registry to FormRoot in place of createDefaultRegistry(). Texaryn
renders native HTML with Bootstrap 5.3 classes; it does not load Bootstrap CSS
or JavaScript itself. The CSS import assumes a bundler that supports it.
Material UI v9
Section titled “Material UI v9”Add the widget package, Material UI and its default styling engine:
pnpm add @texaryn/react-mui @mui/material @emotion/react @emotion/styledimport { createMuiRegistry } from '@texaryn/react-mui'
const registry = createMuiRegistry()Pass registry to FormRoot. The widgets use Material UI v9. The application
owns its theme and any ThemeProvider or CssBaseline; Texaryn adds neither.
Both widget packages require the React binding. Other frameworks use their own default widgets or custom registries.
Emotion
Section titled “Emotion”The examples below assume application-owned CSS variables: --tx-text,
--tx-border-strong, --tx-surface-raised and --tx-accent. Define them on
your styling scope or replace them with colors from your theme.
Use an Emotion styled wrapper and descendant selectors to scope CSS to the rendered form:
import styled from '@emotion/styled'
const EmotionForm = styled.div` color: var(--tx-text);
& label { display: block; margin-bottom: 0.25rem; font-weight: 600; }
& input:not([type='checkbox']), & select, & textarea { box-sizing: border-box; width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--tx-border-strong); border-radius: 0.375rem; background: var(--tx-surface-raised); color: var(--tx-text); }`The playground’s Emotion option shows this approach around the default registry. Its styles stay inside the rendered form surface.
Tailwind CSS
Section titled “Tailwind CSS”In a Vite application, install tailwindcss and @tailwindcss/vite, add the
Tailwind plugin, and import its theme and utility layers. Tailwind’s Preflight
resets global element styles, so an existing application can omit that layer
and avoid changing unrelated renderers. See the Vite installation
guide and Preflight
configuration.
@layer theme, base, components, utilities;@import "tailwindcss/theme.css" layer(theme);@import "tailwindcss/utilities.css" layer(utilities);Put utilities on a wrapper and use arbitrary variants to target the semantic elements rendered by Texaryn:
const formClasses = [ 'space-y-3 font-sans text-sm text-[var(--tx-text)]', '[&_label]:mb-1 [&_label]:block [&_label]:font-medium', '[&_input:not([type=checkbox])]:w-full [&_input:not([type=checkbox])]:rounded-md', '[&_button]:rounded-md [&_button]:bg-[var(--tx-accent)] [&_button]:px-3 [&_button]:py-2',].join(' ')
<div className={formClasses}> <FormRoot registry={createDefaultRegistry()} /></div>The playground’s Tailwind option uses the same default registry and applies generated utilities within a wrapper. Both styling options retain the same runtime data, accessible labels, and control behavior when selected.