Ordered and unordered lists feature to CKEditor 5.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advanced list styling capabilities including list styles, start index, and reversed numbering for enhanced list customization.
Main plugin that adds list styling capabilities to CKEditor 5.
/**
* The list properties feature.
* This is a "glue" plugin that loads the list properties editing feature and list properties UI feature.
*/
class ListProperties extends Plugin {
/** @inheritDoc */
static get requires(): readonly [typeof ListPropertiesEditing, typeof ListPropertiesUI];
/** @inheritDoc */
static get pluginName(): "ListProperties";
/** @inheritDoc */
static override get isOfficialPlugin(): true;
}Core editing functionality for list properties including style, start, and reversed attributes.
/**
* The editing part of the list properties feature. It handles creating, editing and removing list properties.
*/
class ListPropertiesEditing extends Plugin {
/** @inheritDoc */
static get pluginName(): "ListPropertiesEditing";
/** @inheritDoc */
static get requires(): readonly [typeof ListEditing, typeof ListPropertiesUtils];
}Attribute Strategy Type:
interface AttributeStrategy {
scope: 'list' | 'listItem';
attributeName: string;
defaultValue: unknown;
viewConsumables: Array<string>;
modelToViewConverter: (attributeValue: unknown, conversionApi: DowncastConversionApi) => void;
upcastConverter: (element: ViewElement, conversionApi: UpcastConversionApi) => boolean;
}User interface for list properties including dropdowns and forms.
/**
* The list properties UI feature. It introduces the list properties dropdown to the toolbar.
*/
class ListPropertiesUI extends Plugin {
/** @inheritDoc */
static get pluginName(): "ListPropertiesUI";
/** @inheritDoc */
static get requires(): readonly [typeof ListPropertiesEditing];
}Utility functions for list properties operations.
/**
* A set of helpers related to list properties.
*/
class ListPropertiesUtils extends Plugin {
/** @inheritDoc */
static get pluginName(): "ListPropertiesUtils";
/**
* Gets the normalized configuration for the given list type.
*/
getNormalizedConfig(listType: ListPropertiesStyleListType): NormalizedListPropertiesConfig;
/**
* Gets all supported style types for the given list type.
*/
getAllSupportedStyleTypes(listType: ListPropertiesStyleListType): Array<string>;
}Changes list style (disc, decimal, etc.).
/**
* The list style command. It changes the `listStyle` attribute of the selected list items.
*/
class ListStyleCommand extends Command {
/**
* @inheritDoc
*/
constructor(editor: Editor);
/**
* Executes the list style command.
* @param options Command execution options
* @param options.type The list style type to apply
*/
execute(options?: { type?: string }): void;
/**
* The current value of the command.
*/
value: string | null;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Sets start index for numbered lists.
/**
* The list start command. It changes the `listStart` attribute of the selected list items.
*/
class ListStartCommand extends Command {
/**
* @inheritDoc
*/
constructor(editor: Editor);
/**
* Executes the list start command.
* @param options Command execution options
* @param options.startIndex The starting index value
*/
execute(options?: { startIndex?: number }): void;
/**
* The current value of the command.
*/
value: number | null;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Toggles reversed numbering for numbered lists.
/**
* The list reversed command. It changes the `listReversed` attribute of the selected list items.
*/
class ListReversedCommand extends Command {
/**
* @inheritDoc
*/
constructor(editor: Editor);
/**
* Executes the list reversed command.
* @param options Command execution options
* @param options.reversed Whether the list should be reversed
*/
execute(options?: { reversed?: boolean }): void;
/**
* The current value of the command.
*/
value: boolean | null;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Main UI view for list properties form.
/**
* The list properties view.
*/
class ListPropertiesView extends View {
/**
* Creates an instance of the list properties view.
*/
constructor(locale: Locale, options: ListPropertiesViewOptions);
/**
* Focuses the view.
*/
focus(): void;
}Events:
interface ListPropertiesViewListStartEvent {
readonly name: 'listStart';
readonly args: [data: { startIndex: number }];
}
interface ListPropertiesViewListReversedEvent {
readonly name: 'listReversed';
readonly args: [data: { reversed: boolean }];
}View component for style selection.
/**
* The styles view for list properties.
*/
class StylesView extends View {
/**
* Creates an instance of the styles view.
*/
constructor(locale: Locale, styleDefinitions: Array<ListStyleDefinition>);
}interface ListPropertiesConfig {
styles?: boolean | ListPropertiesStyleConfig | ArrayOrItem<ListPropertiesStyleListType>;
startIndex?: boolean;
reversed?: boolean;
}
interface ListPropertiesStyleConfig {
listTypes?: ArrayOrItem<ListPropertiesStyleListType>;
useAttribute?: boolean;
listStyleTypes?: ListStyleTypesConfig;
}
interface ListStyleTypesConfig {
numbered?: Array<NumberedListStyleType>;
bulleted?: Array<BulletedListStyleType>;
}
interface NormalizedListPropertiesConfig {
styles: {
[key in ListPropertiesStyleListType]: Array<string>;
};
startIndex: boolean;
reversed: boolean;
useAttribute: boolean;
}type ListPropertiesStyleListType = 'numbered' | 'bulleted';
type NumberedListStyleType =
| 'decimal'
| 'decimal-leading-zero'
| 'lower-roman'
| 'upper-roman'
| 'lower-latin'
| 'upper-latin';
type BulletedListStyleType =
| 'disc'
| 'circle'
| 'square';import { ClassicEditor } from "@ckeditor/ckeditor5-editor-classic";
import { List, ListProperties } from "@ckeditor/ckeditor5-list";
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [List, ListProperties],
toolbar: ['numberedList', 'bulletedList'],
list: {
properties: {
styles: true,
startIndex: true,
reversed: true
}
}
})
.then(editor => {
console.log('Editor with list properties initialized');
});ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [List, ListProperties],
list: {
properties: {
styles: {
listTypes: ['numbered', 'bulleted'],
useAttribute: false,
listStyleTypes: {
numbered: ['decimal', 'lower-roman', 'upper-roman'],
bulleted: ['disc', 'circle']
}
},
startIndex: true,
reversed: true
}
}
});// Get list property commands
const styleCommand = editor.commands.get('listStyle');
const startCommand = editor.commands.get('listStart');
const reversedCommand = editor.commands.get('listReversed');
// Apply different styles
styleCommand.execute({ type: 'lower-roman' });
startCommand.execute({ startIndex: 5 });
reversedCommand.execute({ reversed: true });
// Check current values
console.log('Current style:', styleCommand.value);
console.log('Current start index:', startCommand.value);
console.log('Is reversed:', reversedCommand.value);import { Plugin } from 'ckeditor5/src/core';
class CustomListStylePlugin extends Plugin {
static get requires() {
return [ListProperties];
}
init() {
const editor = this.editor;
// Add custom toolbar button for specific style
editor.ui.componentFactory.add('romanList', locale => {
const button = new ButtonView(locale);
const command = editor.commands.get('listStyle');
button.set({
label: 'Roman Numerals',
icon: romanIcon,
tooltip: true,
isToggleable: true
});
button.bind('isOn').to(command, 'value', value => value === 'lower-roman');
button.bind('isEnabled').to(command, 'isEnabled');
button.on('execute', () => {
if (command.value === 'lower-roman') {
command.execute({ type: null }); // Remove style
} else {
command.execute({ type: 'lower-roman' });
}
});
return button;
});
}
}// Listen to property command changes
const commands = ['listStyle', 'listStart', 'listReversed'];
commands.forEach(commandName => {
const command = editor.commands.get(commandName);
command.on('change:value', () => {
console.log(`${commandName} changed to:`, command.value);
});
command.on('change:isEnabled', () => {
console.log(`${commandName} enabled:`, command.isEnabled);
});
});
// Update UI based on property states
function updatePropertyUI() {
const styleCommand = editor.commands.get('listStyle');
const startCommand = editor.commands.get('listStart');
const reversedCommand = editor.commands.get('listReversed');
// Update style dropdown
const styleDropdown = document.querySelector('#style-dropdown');
styleDropdown.value = styleCommand.value || '';
styleDropdown.disabled = !styleCommand.isEnabled;
// Update start index input
const startInput = document.querySelector('#start-input');
startInput.value = startCommand.value || 1;
startInput.disabled = !startCommand.isEnabled;
// Update reversed checkbox
const reversedCheckbox = document.querySelector('#reversed-checkbox');
reversedCheckbox.checked = reversedCommand.value || false;
reversedCheckbox.disabled = !reversedCommand.isEnabled;
}
editor.model.document.selection.on('change', updatePropertyUI);Install with Tessl CLI
npx tessl i tessl/npm-ckeditor--ckeditor5-list