Textarea with syntax highlighting powered by solid-js and shiki.
screen-recording.mp4
npm i shiki solid-shiki-textarea
# or
yarn add shiki solid-shiki-textarea
# or
pnpm add shiki solid-shiki-textarea
The main export of solid-shiki-textarea
is a solid component.
Prop Types
import type { LanguageRegistration, ThemeRegistration } from 'shiki'
import type { Language, Theme } from 'shiki-textarea/tm'
type LanguageProps = Language | LanguageRegistration[] | Promise<LanguageRegistration[]>
type ThemeProps = Theme | ThemeRegistration | Promise<ThemeRegistration>
interface ShikiTextareaProps extends Omit<ComponentProps<'div'>, 'style'> {
language: LanguageProps
theme: ThemeProps
code: string
editable?: boolean
style?: JSX.CSSProperties
onInput?: (event: InputEvent & { currentTarget: HTMLTextAreaElement }) => void
}
Static import of theme/language
import { ShikiTextarea } from 'solid-shiki-textarea'
import minLight from 'shiki/themes/min-light.mjs'
import tsx from 'shiki/langs/tsx.mjs'
export default () => (
<ShikiTextarea
language={tsx}
theme={minLight}
code="const sum = (a: string, b: string) => a + b"
editable={true}
style={{
padding: '10px',
'font-size': '16pt',
}}
onInput={e => console.log(e.currentTarget.value)}
/>
)
Dynamic import of theme/language
import { ShikiTextarea } from 'solid-shiki-textarea'
export default () => (
<ShikiTextarea
language={import('https://esm.sh/shiki/langs/tsx.mjs')}
theme={import('https://esm.sh/shiki/themes/min-light.mjs')}
code="const sum = (a: string, b: string) => a + b"
editable={true}
style={{
padding: '10px',
'font-size': '16pt',
}}
onInput={e => console.log(e.currentTarget.value)}
/>
)
We also export a custom-element wrapper <shiki-textarea/>
powered by
@lume/element
Attribute Types
import { LanguageProps, ThemeProps } from 'shiki-textarea'
interface ShikiTextareaAttributes extends ComponentProps<'div'> {
language?: LanguageProps
theme?: ThemeProps
code?: string
editable?: boolean
stylesheet?: string | CSSStyleSheet
onInput?: (event: InputEvent & { currentTarget: ShikiTextareaElement }) => void
}
import { setCDN } from 'solid-shiki-textarea'
import 'solid-shiki-textarea/custom-element'
setCDN('/shiki')
export default () => (
<shiki-textarea
language="tsx"
theme="andromeeda"
code="const sum = (a: string, b: string) => a + b"
editable={true}
style={{
padding: '10px',
'font-size': '16pt',
}}
stylesheet="code, code * { font-style:normal; }"
onInput={e => console.log(e.currentTarget.value)}
/>
)
Some DOM ::part()
are exported.
root
can be used to override thebackground
, set apadding
or changefont-size
andline-height
.textarea
can be used to change the selection color.code
can be used to change thecode
tag.
shiki-textarea::part(root) {
padding: 20px;
background: transparent;
font-size: 18px;
line-height: 1.25;
}
shiki-textarea::part(textarea)::selection {
background: deepskyblue;
}
/* to size it to the container, will remove dead-zones */
shiki-textarea {
min-height: 100%;
min-width: 100%;
}
The attribute stylesheet
could be used as a last resort to customize the theme. In the following
example we avoid italics in the rendered coded. The stylesheet is created, cached and reused on the
different shiki-textarea
instances.
<shiki-textarea
language="tsx"
theme="andromeeda"
code="const sum = (a: string, b: string) => a + b"
editable={true}
style={{
'--padding': '10px',
'font-size': '16pt',
}}
stylesheet="code, code * { font-style:normal; }"
onInput={e => console.log(e.target.value)}
/>
// from solid component
import { setCDN } from 'solid-shiki-textarea'
// Set base-url of CDN directly (defaults to https://esm.sh)
setCDN('https://unpkg.com')
// relative to the root
setCDN('/assets/shiki')
// Or use the callback-form
setCDN((type, id) => `./shiki/${type}/${id}.json`)
Both, the languages and themes list are exported as string[]
.
import type { Theme, Language } from 'solid-shiki-textarea/tm'
import { themes, languages } from 'solid-shiki-textarea/tm'