Appearance
TextField — usage examples
Not on npm yet
@rozie-ui/text-field is not yet on npm for any framework target — it is still in dogfooding across all six.
TextField is designed to ship as six pre-compiled, per-framework packages from a single .rozie source, but none has published to npm yet. The snippets below show the idiomatic consumption code for each target's workspace build — for review, not yet installable.
Usage
tsx
// @rozie-ui/text-field-react is not yet published to npm — this shows the workspace build, for review only.
import { useState } from 'react';
import { TextField } from '@rozie-ui/text-field-react';
export function Demo() {
const [email, setEmail] = useState('');
const error = email && !email.includes('@') ? 'Enter a valid email address.' : '';
return (
<TextField
modelValue={email}
onModelValueChange={setEmail}
label="Email"
type="email"
description="We never share it."
error={error}
required
/>
);
}
// A textarea that grows with its content, with a character counter.
export function NotesDemo() {
const [notes, setNotes] = useState('');
return (
<TextField
modelValue={notes}
onModelValueChange={setNotes}
label="Notes"
multiline
autosize
maxRows={8}
maxLength={500}
showCount
/>
);
}vue
<!-- @rozie-ui/text-field-vue is not yet published to npm — this shows the workspace build, for review only. -->
<script setup lang="ts">
import { computed, ref } from 'vue';
import TextField from '@rozie-ui/text-field-vue';
const email = ref('');
const error = computed(() => (email.value && !email.value.includes('@') ? 'Enter a valid email address.' : ''));
const notes = ref('');
</script>
<template>
<TextField v-model:modelValue="email" label="Email" type="email"
description="We never share it." :error="error" required />
<!-- A textarea that grows with its content, with a character counter -->
<TextField v-model:modelValue="notes" label="Notes" multiline autosize
:max-rows="8" :max-length="500" show-count />
</template>svelte
<!-- @rozie-ui/text-field-svelte is not yet published to npm — this shows the workspace build, for review only. -->
<script lang="ts">
import TextField from '@rozie-ui/text-field-svelte';
let email = $state('');
let notes = $state('');
const error = $derived(email && !email.includes('@') ? 'Enter a valid email address.' : '');
</script>
<TextField bind:modelValue={email} label="Email" type="email"
description="We never share it." {error} required />
<!-- A textarea that grows with its content, with a character counter -->
<TextField bind:modelValue={notes} label="Notes" multiline autosize maxRows={8} maxLength={500} showCount />ts
// @rozie-ui/text-field-angular is not yet published to npm — this shows the workspace build, for review only.
import { Component } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { TextField } from '@rozie-ui/text-field-angular';
@Component({
selector: 'app-demo',
standalone: true,
imports: [TextField, ReactiveFormsModule],
template: `
<!-- TextField is a ControlValueAccessor: bind it like any form control. -->
<rozie-text-field [formControl]="email" label="Email" type="email" description="We never share it."
[error]="email.touched && email.invalid ? 'Enter a valid email address.' : ''" [required]="true" />
<!-- Or two-way bind the model directly. -->
<rozie-text-field [(modelValue)]="notes" label="Notes" [multiline]="true" [autosize]="true" [maxRows]="8" />
`,
})
export class DemoComponent {
email = new FormControl('', [Validators.required, Validators.email]);
notes = '';
}tsx
// @rozie-ui/text-field-solid is not yet published to npm — this shows the workspace build, for review only.
import { createSignal } from 'solid-js';
import { TextField } from '@rozie-ui/text-field-solid';
export function Demo() {
const [email, setEmail] = createSignal('');
const error = () => (email() && !email().includes('@') ? 'Enter a valid email address.' : '');
return (
<TextField
modelValue={email()}
onModelValueChange={setEmail}
label="Email"
type="email"
description="We never share it."
error={error()}
required
/>
);
}ts
// @rozie-ui/text-field-lit is not yet published to npm — this shows the workspace build, for review only.
import '@rozie-ui/text-field-lit';
// <rozie-text-field> is a custom element. Set props as properties (or kebab-case
// attributes), and listen for `model-value-change` to receive each keystroke as
// the two-way model, or `change` for a committed edit.
const el = document.querySelector('rozie-text-field');
el.label = 'Email';
el.type = 'email';
el.required = true;
el.addEventListener('model-value-change', (e) => {
el.modelValue = e.detail;
el.error = e.detail && !e.detail.includes('@') ? 'Enter a valid email address.' : '';
});
// The control and its label live in the element's shadow root, so they label
// each other there. A native <form> does not see the inner input: read
// `modelValue` when you submit.Imperative handle
Beyond props and events, TextField exposes imperative methods (declared once in the .rozie source via $expose). Grab a handle through your framework's native ref mechanism and call them directly:
tsx
// @rozie-ui/text-field-react is not yet published to npm — this shows the workspace build, for review only.
import { useRef } from 'react';
import { TextField, type TextFieldHandle } from '@rozie-ui/text-field-react';
const field = useRef<TextFieldHandle>(null);
// <TextField ref={field} ... />
field.current?.focus();
field.current?.select();
field.current?.clear();vue
<!-- @rozie-ui/text-field-vue is not yet published to npm — this shows the workspace build, for review only. -->
<script setup lang="ts">
import { ref } from 'vue';
const field = ref(); // template ref
</script>
<template>
<TextField ref="field" v-model:modelValue="text" label="Search" />
<button @click="field.clear()">Clear</button>
</template>svelte
<!-- @rozie-ui/text-field-svelte is not yet published to npm — this shows the workspace build, for review only. -->
<script lang="ts">
let field; // component instance via bind:this
</script>
<TextField bind:this={field} bind:modelValue={text} label="Search" />
<button onclick={() => field.clear()}>Clear</button>ts
// @rozie-ui/text-field-angular is not yet published to npm — this shows the workspace build, for review only.
export class DemoComponent {
@ViewChild(TextField) field!: TextField; // or the viewChild() signal
reset() { this.field.clear(); this.field.focus(); }
}tsx
// @rozie-ui/text-field-solid is not yet published to npm — this shows the workspace build, for review only.
import { TextField, type TextFieldHandle } from '@rozie-ui/text-field-solid';
let handle: TextFieldHandle | undefined;
<TextField ref={(h) => (handle = h)} modelValue={text()} onModelValueChange={setText} label="Search" />;
handle?.clear();ts
// @rozie-ui/text-field-lit is not yet published to npm — this shows the workspace build, for review only.
// The custom element IS the handle: exposed methods are public element methods.
const el = document.querySelector('rozie-text-field');
el.focus(); // moves focus into the inner control
el.select();
el.clear();See also
- TextField — showcase & API — the full prop / event / slot / handle reference, theming, and accessibility.
- TextField theming — the complete customizable-token table.
- TextField comparison — how it stacks up against the per-framework libraries.
- TextField — live demo — the real package running in the page, plus the one
.roziesource and all six generated outputs.