Textarea
Textareaは、複数行のテキストを入力する際に使用されるコンポーネントです。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
</script>
<Textarea placeholder="プレースホルダー"></Textarea>
プロパティ
Textareaは、以下のプロパティをサポートしています。
| 名前 | 型 | デフォルト値 | 説明 |
|---|---|---|---|
isError |
boolean |
false |
true の場合エラー時のスタイルを適用します。 |
readonly |
boolean |
false |
指定すると読み取り専用の状態です。 |
disabled |
boolean |
false |
指定するとグレーアウトされ、クリック不可になります。 |
インストールの手順
以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。
atoms/Textarea.svelte
<!--
@component
## 概要
- textareaタグと同様に複数行のテキストを入力する際に使用されるコンポーネントです
## 機能
- 複数行のプレーンテキスト編集が可能です
- 見た目を変更するためのいくつかのスタイル用Propsが追加されています(詳細はPropsセクションを参照)
## Props
- isError: true の場合エラー時のスタイルを適用します
- readonly: 指定すると読み取り専用の状態です
- disabled: 指定するとグレーアウトされ、クリック不可になります
## Usage
```svelte
<Textarea placeholder="プレースホルダー" bind:value />
```
-->
<script module lang="ts">
import type { ClassValue, HTMLTextareaAttributes } from 'svelte/elements';
import { cva, type VariantProps } from 'class-variance-authority';
export const textareaVariants = cva('w-full min-h-20 px-3 py-2 bg-surface border rounded-md text-foreground text-sm outline-offset-2 outline-ring transition-colors [&:not(:disabled):not([readonly])]:hover:bg-accent/90 placeholder:text-muted-foreground focus-visible:outline-2', {
variants: {
/** エラーかどうか */
isError: {
true: ['border-destructive'],
false: ['border-input'],
},
/** 操作できるかどうか */
disabled: {
true: ['opacity-50 cursor-not-allowed'],
false: ['cursor-text'],
},
/** 読み取り専用かどうか */
readonly: {
true: ['opacity-50'],
false: [],
},
},
defaultVariants: {
isError: false,
disabled: false,
readonly: false,
},
});
export type TextareaVariants = VariantProps<typeof textareaVariants>;
export interface TextareaProps extends TextareaVariants, HTMLTextareaAttributes {
/** クラス */
class?: ClassValue;
/** 内部で使用するため指定できません */
'data-rabee-ui'?: never;
}
</script>
<script lang="ts">
let {
isError = false,
disabled = false,
readonly = false,
class: className,
value = $bindable(''),
...textareaAttributes
}: TextareaProps = $props();
let textareaElement = $state<HTMLTextAreaElement>();
let textareaVariantClass = $derived(textareaVariants({ disabled, readonly, isError, class: className }));
// 動的に挿入された場合でも autofocus を有効にする
$effect(() => {
if (textareaAttributes.autofocus && textareaElement) {
textareaElement.focus();
}
});
</script>
<textarea class={textareaVariantClass} {disabled} {readonly} {...textareaAttributes} bind:value bind:this={textareaElement} data-rabee-ui="textarea"></textarea>
使い方
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
</script>
<Textarea placeholder="プレースホルダー"></Textarea>
サンプル
Default
特に操作が行われていない、デフォルトの状態です。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
</script>
<Textarea placeholder="プレースホルダー"></Textarea>
Readonly
内容を編集できない、読み取り専用の状態です。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
let value = $state('');
</script>
<Textarea readonly placeholder="プレースホルダー" bind:value />
Error
入力内容に問題があり、エラーが表示されている状態です。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
let value = $state('');
let isError = $derived(value === '');
</script>
<div class="w-full">
<Textarea placeholder="プレースホルダー" bind:value isError />
{#if isError}
<p class="text-destructive text-sm mt-2">ここにエラーメッセージが入ります。</p>
{/if}
</div>
Disabled
利用不可の状態です。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
let value = $state('');
</script>
<Textarea placeholder="プレースホルダー" disabled bind:value />
With Label
ラベルと組み合わせることも可能です。
<script lang="ts">
import Label from '$lib/components/ui/atoms/Label.svelte';
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
let value = $state('');
</script>
<div class="w-full">
<Label class="mb-1.5" for="textarea">ラベル</Label>
<p class="text-muted-foreground mb-2 text-sm">ここに補足文が入ります。</p>
<Textarea id="textarea" placeholder="プレースホルダー" bind:value />
</div>
Max Length
入力可能な最大文字数を設定し、超えるとエラーが表示されます。
<script lang="ts">
import Textarea from '$lib/components/ui/atoms/Textarea.svelte';
let value = $state('');
let isError = $derived(value.length > 10);
let maxlength = 10;
let overTexts = $derived(maxlength - value.length);
</script>
<div class="flex flex-col w-full gap-4">
<div>
<Textarea placeholder="プレースホルダー" {isError} bind:value />
<div class="flex items-start justify-between w-full gap-2 mt-2">
<div>
{#if isError}
<p class="text-destructive text-sm">ここにエラーメッセージが入ります。</p>
{/if}
</div>
<p class="shrink-0 text-sm/normal">
<span class={[isError && 'text-destructive', 'mr-0.5']}>{value.length}</span><span class="text-subtle-foreground">/{maxlength}</span>
</p>
</div>
</div>
<div>
<Textarea placeholder="プレースホルダー" {isError} bind:value />
<div class="flex items-start justify-between w-full gap-2 mt-2">
<div>
{#if isError}
<p class="text-destructive text-sm">ここにエラーメッセージが入ります。</p>
{/if}
</div>
<p class="shrink-0 text-sm/normal">
{#if isError}
<span class="text-destructive mr-0.5">{overTexts}</span>
{:else}
<span class="mr-0.5">{value.length}</span><span class="text-subtle-foreground">/{maxlength}</span>
{/if}
</p>
</div>
</div>
</div>