Input
A text input component for forms and user data entry with built-in styling and accessibility features.
import { Input } from '#app/ui/input.tsx'
export function InputDemo() {
return () => <Input type="email" placeholder="Email" />
}import { Input } from '#app/ui/input.tsx'
export function InputDemo() {
return () => <Input type="email" placeholder="Email" />
}Installation
$ bunx --bun shadcn@latest add https://www.shadcn-remix.com/r/input.json$ npx shadcn@latest add https://www.shadcn-remix.com/r/input.json$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/input.json$ yarn dlx shadcn@latest add https://www.shadcn-remix.com/r/input.jsonInstall the following dependencies:
$ bun add remix$ npm install remix$ pnpm add remix$ yarn add remixCopy and paste the following code into your project.
import { css, type Handle, type Props } from 'remix/component'
export type InputProps = Props<'input'>
const inputStyles = css({
height: '2.25rem',
width: '100%',
minWidth: 0,
borderRadius: 'calc(var(--radius) - 2px)',
borderWidth: '1px',
borderColor: 'var(--input)',
backgroundColor: 'transparent',
paddingInline: '0.75rem',
paddingBlock: '0.25rem',
fontSize: '1rem',
lineHeight: 1.5,
'--tw-shadow': '0 1px 2px 0 rgb(0 0 0 / 0.05)',
boxShadow: 'var(--tw-ring-shadow), var(--tw-shadow)',
transitionProperty: 'color, box-shadow',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDuration: '150ms',
outlineStyle: 'none',
'& *::selection, &::selection': {
backgroundColor: 'var(--primary)',
color: 'var(--primary-foreground)',
},
'&::file-selector-button': {
display: 'inline-flex',
height: '1.75rem',
borderWidth: 0,
backgroundColor: 'transparent',
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
fontWeight: 500,
color: 'var(--foreground)',
},
'&::placeholder': { color: 'var(--muted-foreground)' },
'&:disabled': { pointerEvents: 'none', cursor: 'not-allowed', opacity: 0.5 },
'@media (min-width: 48rem)': { fontSize: '0.875rem', lineHeight: 'calc(1.25 / 0.875)' },
'.dark &': { backgroundColor: 'color-mix(in oklab, var(--input) 30%, transparent)' },
'&:focus-visible': {
borderColor: 'var(--ring)',
'--tw-ring-shadow':
'0 0 0 3px var(--tw-ring-color, color-mix(in oklab, var(--ring) 50%, transparent))',
},
'&[aria-invalid="true"]': {
borderColor: 'var(--destructive)',
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 20%, transparent)',
},
'.dark &[aria-invalid="true"]': {
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 40%, transparent)',
},
})
export function Input(handle: Handle<InputProps>) {
return () => {
let { mix, ...props } = handle.props
return <input data-slot="input" {...props} mix={[inputStyles, mix]} />
}
}Update the import paths to match your project setup.
Usage
import { Input } from '#app/ui/input.tsx'<Input />Examples
Disabled
Use the disabled prop to disable the input. To style the disabled state, add the data-disabled attribute to the Field component.
import { Input } from '#app/ui/input.tsx'
export function InputDisabled() {
return () => <Input disabled type="email" placeholder="Email" />
}import { Input } from '#app/ui/input.tsx'
export function InputDisabled() {
return () => <Input disabled type="email" placeholder="Email" />
}File
Use the type="file" prop to create a file input.
import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({
display: 'grid',
width: '100%',
maxWidth: '24rem',
alignItems: 'center',
gap: '0.75rem',
})
export function InputFile() {
return () => (
<div mix={gridStyles}>
<Label htmlFor="picture">Picture</Label>
<Input id="picture" type="file" />
</div>
)
}With button
import { css } from 'remix/component'
import { Button } from '#app/ui/button.tsx'
import { Input } from '#app/ui/input.tsx'
const rowStyles = css({import { css } from 'remix/component'
import { Button } from '#app/ui/button.tsx'
import { Input } from '#app/ui/input.tsx'
const rowStyles = css({
display: 'flex',
width: '100%',
maxWidth: '24rem',
alignItems: 'center',
gap: '0.5rem',
})
export function InputWithButton() {
return () => (
<div mix={rowStyles}>
<Input type="email" placeholder="Email" />
<Button type="submit" variant="outline">
Subscribe
</Button>
</div>
)
}With label
import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({
display: 'grid',
width: '100%',
maxWidth: '24rem',
alignItems: 'center',
gap: '0.75rem',
})
export function InputWithLabel() {
return () => (
<div mix={gridStyles}>
<Label htmlFor="email">Email</Label>
<Input type="email" id="email" placeholder="Email" />
</div>
)
}With text
Enter your email address.
import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({import { css } from 'remix/component'
import { Input } from '#app/ui/input.tsx'
import { Label } from '#app/ui/label.tsx'
const gridStyles = css({
display: 'grid',
width: '100%',
maxWidth: '24rem',
alignItems: 'center',
gap: '0.75rem',
})
const mutedStyles = css({
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
color: 'var(--muted-foreground)',
})
export function InputWithText() {
return () => (
<div mix={gridStyles}>
<Label htmlFor="email-2">Email</Label>
<Input type="email" id="email-2" placeholder="Email" />
<p mix={mutedStyles}>Enter your email address.</p>
</div>
)
}API Reference
Input
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |